diff options
author | Prabir Pradhan <prabirmsp@google.com> | 2023-09-14 22:28:32 +0000 |
---|---|---|
committer | Prabir Pradhan <prabirmsp@google.com> | 2023-09-20 13:02:28 +0000 |
commit | f1198587dd09c5917300f5da9b95e48d28848002 (patch) | |
tree | 66f71e3c5729c5845556e248dd6099be9e0b0520 | |
parent | 92fc9071be0bf8439e7d5f080d8ffd1f398a9c49 (diff) | |
download | native-f1198587dd09c5917300f5da9b95e48d28848002.tar.gz |
Stylus fusion: Use SOURCE_BLUETOOTH_STYLUS dynamically for events
Previously, whenever an external stylus was connected, the source for
all touch devices (touchscreens, styluses, drawing tablets, etc.) would
change to include SOURCE_BLUETOOTH_STYLUS. This meant that all events
produced by these devices would also include SOURCE_BLUETOOTH_STYLUS,
even if the event was unaltered by stylus fusion.
In this CL, we introduce a way to dynamically add
SOURCE_BLUETOOTH_STYLUS to event streams that are a product of stylus
fusion.
The problem we are trying to solve is to be able to differentiate a
normal event stream from a stylus vs. an event stream from a stylus or
touchscreen that has additional information fused from a bluetooth
device. Previously, both such streams would have
SOURCE_BLUETOOTH_STYLUS, whereas now, only the latter case would use
that source.
Bug: 300473125
Test: atest inputflinger_test
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:b08a0e84208886a3192803745b48c0d348578e31)
Merged-In: I3526d42df68bc899c8e9a0e5ad69c95864f4c325
Change-Id: I3526d42df68bc899c8e9a0e5ad69c95864f4c325
-rw-r--r-- | services/inputflinger/reader/mapper/TouchInputMapper.cpp | 21 | ||||
-rw-r--r-- | services/inputflinger/reader/mapper/TouchInputMapper.h | 2 | ||||
-rw-r--r-- | services/inputflinger/tests/InputReader_test.cpp | 84 |
3 files changed, 70 insertions, 37 deletions
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index f2b0a4b0a7..587e8450b1 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -130,7 +130,10 @@ TouchInputMapper::TouchInputMapper(InputDeviceContext& deviceContext, TouchInputMapper::~TouchInputMapper() {} uint32_t TouchInputMapper::getSources() const { - return mSource; + // The SOURCE_BLUETOOTH_STYLUS is added to events dynamically if the current stream is modified + // by the external stylus state. That's why we don't add it directly to mSource during + // configuration. + return mSource | (hasExternalStylus() ? AINPUT_SOURCE_BLUETOOTH_STYLUS : 0); } void TouchInputMapper::populateDeviceInfo(InputDeviceInfo& info) { @@ -932,9 +935,6 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) if (hasStylus()) { mSource |= AINPUT_SOURCE_STYLUS; } - if (hasExternalStylus()) { - mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS; - } } else if (mParameters.deviceType == Parameters::DeviceType::TOUCH_NAVIGATION) { mSource = AINPUT_SOURCE_TOUCH_NAVIGATION; mDeviceMode = DeviceMode::NAVIGATION; @@ -1653,6 +1653,10 @@ std::list<NotifyArgs> TouchInputMapper::cookAndDispatch(nsecs_t when, nsecs_t re mSource, mViewport.displayId, policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState); + if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { + mCurrentStreamModifiedByExternalStylus = false; + } + // Clear some transient state. mCurrentRawState.rawVScroll = 0; mCurrentRawState.rawHScroll = 0; @@ -1704,6 +1708,10 @@ void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) { mExternalStylusButtonsApplied |= pressedButtons; mExternalStylusButtonsApplied &= ~releasedButtons; + + if (mExternalStylusButtonsApplied != 0 || releasedButtons != 0) { + mCurrentStreamModifiedByExternalStylus = true; + } } } @@ -1714,6 +1722,8 @@ void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) { return; } + mCurrentStreamModifiedByExternalStylus = true; + float pressure = lastPointerData.isTouching(*mFusedStylusPointerId) ? lastPointerData.pointerCoordsForId(*mFusedStylusPointerId) .getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) @@ -3813,6 +3823,9 @@ NotifyMotionArgs TouchInputMapper::dispatchMotion( ALOG_ASSERT(false); } } + if (mCurrentStreamModifiedByExternalStylus) { + source |= AINPUT_SOURCE_BLUETOOTH_STYLUS; + } const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE); const bool showDirectStylusPointer = mConfig.stylusPointerIconEnabled && diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index d8b59ca39b..97f41cc57b 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -357,6 +357,8 @@ protected: bool mExternalStylusDataPending; // A subset of the buttons in mCurrentRawState that came from an external stylus. int32_t mExternalStylusButtonsApplied{0}; + // True if the current cooked pointer data was modified due to the state of an external stylus. + bool mCurrentStreamModifiedByExternalStylus{false}; // True if we sent a HOVER_ENTER event. bool mSentHoverEnter{false}; diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 9ccd965dce..8941d16534 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -91,6 +91,9 @@ static constexpr int32_t ACTION_POINTER_1_DOWN = static constexpr int32_t ACTION_POINTER_1_UP = AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); +static constexpr uint32_t STYLUS_FUSION_SOURCE = + AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_BLUETOOTH_STYLUS; + // Minimum timestamp separation between subsequent input events from a Bluetooth device. static constexpr nsecs_t MIN_BLUETOOTH_TIMESTAMP_DELTA = ms2ns(4); // Maximum smoothing time delta so that we don't generate events too far into the future. @@ -2222,6 +2225,22 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonMotionEventsDisable // ongoing stylus gesture that is being emitted by the touchscreen. using ExternalStylusIntegrationTest = BaseTouchIntegrationTest; +TEST_F(ExternalStylusIntegrationTest, ExternalStylusConnectionChangesTouchscreenSource) { + // Create an external stylus capable of reporting pressure data that + // should be fused with a touch pointer. + std::unique_ptr<UinputExternalStylusWithPressure> stylus = + createUinputDevice<UinputExternalStylusWithPressure>(); + ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled()); + const auto stylusInfo = findDeviceByName(stylus->getName()); + ASSERT_TRUE(stylusInfo); + + // Connecting an external stylus changes the source of the touchscreen. + const auto deviceInfo = findDeviceByName(mDevice->getName()); + ASSERT_TRUE(deviceInfo); + ASSERT_TRUE(isFromSource(deviceInfo->getSources(), STYLUS_FUSION_SOURCE)); +} + TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureReported) { const Point centerPoint = mDevice->getCenterPoint(); @@ -2251,17 +2270,17 @@ TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureReport mDevice->sendDown(centerPoint); mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType(ToolType::STYLUS), WithButtonState(0), - WithDeviceId(touchscreenId), WithPressure(100.f / RAW_PRESSURE_MAX)))); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithToolType(ToolType::STYLUS), + WithButtonState(0), WithSource(STYLUS_FUSION_SOURCE), WithDeviceId(touchscreenId), + WithPressure(100.f / RAW_PRESSURE_MAX)))); // Change the pressure on the external stylus, and ensure the touchscreen generates a MOVE // event with the updated pressure. stylus->setPressure(200); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithToolType(ToolType::STYLUS), WithButtonState(0), - WithDeviceId(touchscreenId), WithPressure(200.f / RAW_PRESSURE_MAX)))); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithToolType(ToolType::STYLUS), + WithButtonState(0), WithSource(STYLUS_FUSION_SOURCE), WithDeviceId(touchscreenId), + WithPressure(200.f / RAW_PRESSURE_MAX)))); // The external stylus did not generate any events. ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled()); @@ -2306,8 +2325,8 @@ TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureNotRep // it shows up as a finger pointer. ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType(ToolType::FINGER), WithDeviceId(touchscreenId), - WithPressure(1.f)))); + WithSource(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS), + WithToolType(ToolType::FINGER), WithDeviceId(touchscreenId), WithPressure(1.f)))); // Change the pressure on the external stylus. Since the pressure was not present at the start // of the gesture, it is ignored for now. @@ -2319,6 +2338,7 @@ TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureNotRep mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithSource(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS), WithToolType(ToolType::FINGER)))); // Start a new gesture. Since we have a valid pressure value, it shows up as a stylus. @@ -2327,9 +2347,9 @@ TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureNotRep mDevice->sendDown(centerPoint); mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType(ToolType::STYLUS), WithButtonState(0), - WithDeviceId(touchscreenId), WithPressure(200.f / RAW_PRESSURE_MAX)))); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithSource(STYLUS_FUSION_SOURCE), + WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId), + WithPressure(200.f / RAW_PRESSURE_MAX)))); // The external stylus did not generate any events. ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled()); @@ -2361,14 +2381,15 @@ TEST_F(ExternalStylusIntegrationTest, DISABLED_UnfusedExternalStylus) { std::chrono::milliseconds(ns2ms(EXTERNAL_STYLUS_DATA_TIMEOUT)); mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE( - mTestListener - ->assertNotifyMotionWasCalled(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType( - ToolType::FINGER), - WithButtonState(0), - WithDeviceId(touchscreenId), - WithPressure(1.f)), - waitUntil)); + mTestListener->assertNotifyMotionWasCalled(AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_DOWN), + WithToolType(ToolType::FINGER), + WithSource(AINPUT_SOURCE_TOUCHSCREEN | + AINPUT_SOURCE_STYLUS), + WithButtonState(0), + WithDeviceId(touchscreenId), + WithPressure(1.f)), + waitUntil)); // The external stylus did not generate any events. ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled()); @@ -7400,12 +7421,10 @@ public: protected: StylusState mStylusState{}; - static constexpr uint32_t EXPECTED_SOURCE = - AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_BLUETOOTH_STYLUS; void testStartFusedStylusGesture(SingleTouchInputMapper& mapper) { auto toolTypeSource = - AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS)); + AllOf(WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS)); // The first pointer is withheld. processDown(mapper, 100, 200); @@ -7439,7 +7458,7 @@ protected: processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(EXPECTED_SOURCE), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS)))); mStylusState.pressure = 0.f; @@ -7449,8 +7468,10 @@ protected: } void testUnsuccessfulFusionGesture(SingleTouchInputMapper& mapper) { + // When stylus fusion is not successful, events should be reported with the original source. + // In this case, it is from a touchscreen. auto toolTypeSource = - AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::FINGER)); + AllOf(WithSource(AINPUT_SOURCE_TOUCHSCREEN), WithToolType(ToolType::FINGER)); // The first pointer is withheld when an external stylus is connected, // and a timeout is requested. @@ -7490,7 +7511,7 @@ private: TEST_F(ExternalStylusFusionTest, UsesBluetoothStylusSource) { SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus(); - ASSERT_EQ(EXPECTED_SOURCE, mapper.getSources()); + ASSERT_EQ(STYLUS_FUSION_SOURCE, mapper.getSources()); } TEST_F(ExternalStylusFusionTest, UnsuccessfulFusion) { @@ -7507,8 +7528,7 @@ TEST_F(ExternalStylusFusionTest, SuccessfulFusion_TouchFirst) { // before the touch is reported by the touchscreen. TEST_F(ExternalStylusFusionTest, SuccessfulFusion_PressureFirst) { SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus(); - auto toolTypeSource = - AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS)); + auto toolTypeSource = AllOf(WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS)); // The external stylus reports pressure first. It is ignored for now. mStylusState.pressure = 1.f; @@ -7550,8 +7570,7 @@ TEST_F(ExternalStylusFusionTest, FusionIsRepeatedForEachNewGesture) { TEST_F(ExternalStylusFusionTest, FusedPointerReportsPressureChanges) { SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus(); - auto toolTypeSource = - AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS)); + auto toolTypeSource = AllOf(WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS)); mStylusState.pressure = 0.8f; processExternalStylusState(mapper); @@ -7612,7 +7631,7 @@ TEST_F(ExternalStylusFusionTest, FusedPointerReportsPressureChanges) { processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(EXPECTED_SOURCE), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS)))); ASSERT_NO_FATAL_FAILURE(mReader->getContext()->assertTimeoutWasNotRequested()); @@ -7621,7 +7640,7 @@ TEST_F(ExternalStylusFusionTest, FusedPointerReportsPressureChanges) { TEST_F(ExternalStylusFusionTest, FusedPointerReportsToolTypeChanges) { SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus(); - auto source = WithSource(EXPECTED_SOURCE); + auto source = WithSource(STYLUS_FUSION_SOURCE); mStylusState.pressure = 1.f; mStylusState.toolType = ToolType::ERASER; @@ -7674,8 +7693,7 @@ TEST_F(ExternalStylusFusionTest, FusedPointerReportsToolTypeChanges) { TEST_F(ExternalStylusFusionTest, FusedPointerReportsButtons) { SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus(); - auto toolTypeSource = - AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS)); + auto toolTypeSource = AllOf(WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS)); ASSERT_NO_FATAL_FAILURE(testStartFusedStylusGesture(mapper)); |