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
Change-Id: I3526d42df68bc899c8e9a0e5ad69c95864f4c325
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index b565454..90bd7c9 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -130,7 +130,10 @@
 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 @@
         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;
@@ -1664,6 +1664,10 @@
                                 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;
@@ -1715,6 +1719,10 @@
 
         mExternalStylusButtonsApplied |= pressedButtons;
         mExternalStylusButtonsApplied &= ~releasedButtons;
+
+        if (mExternalStylusButtonsApplied != 0 || releasedButtons != 0) {
+            mCurrentStreamModifiedByExternalStylus = true;
+        }
     }
 }
 
@@ -1725,6 +1733,8 @@
         return;
     }
 
+    mCurrentStreamModifiedByExternalStylus = true;
+
     float pressure = lastPointerData.isTouching(*mFusedStylusPointerId)
             ? lastPointerData.pointerCoordsForId(*mFusedStylusPointerId)
                       .getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)
@@ -3821,6 +3831,9 @@
             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 &&