Support mouse pointer on external displays (1/3)
If input source is mouse, InputTouchMapper and CursorInputMapper will assign
a PointerController which associated with some display.
When dispatch a motion event, it should be assigned the displayId from
PointerController.
- Add getDisplayId for PointerControllerInterface to get the current
associated display id.
- Add updatePointerDisplay for InputReaderPolicyInterface to find and
associate the specified display viewport.
- Add test cases for TouchInputMapper and CursorInputMapper.
Bug: 113559891
Test: ActivityView test app
Test: atest inputflinger_tests
Change-Id: Ifc69374a55f39fbc1572d9ea3f979fcbb83b45c0
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 9e748d8..9ba4140 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -2638,6 +2638,7 @@
mOrientation = internalViewport->orientation;
}
}
+ getPolicy()->updatePointerDisplay();
bumpGeneration();
}
}
@@ -2783,7 +2784,7 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
- displayId = ADISPLAY_ID_DEFAULT;
+ displayId = mPointerController->getDisplayId();
} else {
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
@@ -3601,6 +3602,9 @@
(mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
if (mPointerController == nullptr) {
mPointerController = getPolicy()->obtainPointerController(getDeviceId());
+ getPolicy()->updatePointerDisplay();
+ } else if (viewportChanged) {
+ getPolicy()->updatePointerDisplay();
}
} else {
mPointerController.clear();
@@ -5387,7 +5391,8 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ int32_t displayId = mPointerController->getDisplayId();
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
@@ -6294,6 +6299,7 @@
void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
bool down, bool hovering) {
int32_t metaState = getContext()->getGlobalMetaState();
+ int32_t displayId = mViewport.displayId;
if (mPointerController != nullptr) {
if (down || hovering) {
@@ -6304,13 +6310,14 @@
} else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
}
+ displayId = mPointerController->getDisplayId();
}
if (mPointerSimple.down && !down) {
mPointerSimple.down = false;
// Send up.
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
/* deviceTimestamp */ 0,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
@@ -6323,7 +6330,7 @@
mPointerSimple.hovering = false;
// Send hover exit.
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
/* deviceTimestamp */ 0,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
@@ -6338,7 +6345,7 @@
mPointerSimple.downTime = when;
// Send down.
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
/* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
@@ -6348,7 +6355,7 @@
}
// Send move.
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
/* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
@@ -6362,7 +6369,7 @@
mPointerSimple.hovering = true;
// Send hover enter.
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
mCurrentRawState.buttonState, 0,
/* deviceTimestamp */ 0,
@@ -6373,7 +6380,7 @@
}
// Send hover move.
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
mCurrentRawState.buttonState, 0,
/* deviceTimestamp */ 0,
@@ -6395,7 +6402,7 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
- NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
/* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &pointerCoords,
@@ -6457,8 +6464,9 @@
ALOG_ASSERT(false);
}
}
-
- NotifyMotionArgs args(when, getDeviceId(), source, mViewport.displayId, policyFlags,
+ int32_t displayId = mPointerController != nullptr ?
+ mPointerController->getDisplayId() : mViewport.displayId;
+ NotifyMotionArgs args(when, getDeviceId(), source, displayId, policyFlags,
action, actionButton, flags, metaState, buttonState, edgeFlags,
deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime);
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index fe1c50b..5a78df7 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -342,6 +342,9 @@
/* Gets the affine calibration associated with the specified device. */
virtual TouchAffineTransformation getTouchAffineTransformation(
const std::string& inputDeviceDescriptor, int32_t surfaceRotation) = 0;
+
+ /* Update the pointer controller associated with the specified display. */
+ virtual void updatePointerDisplay() = 0;
};
} // namespace android
diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h
index e94dd94..e60b3f4 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -58,6 +58,9 @@
/* Gets the absolute location of the pointer. */
virtual void getPosition(float* outX, float* outY) const = 0;
+ /* Gets the id of the display where the pointer should be shown. */
+ virtual int32_t getDisplayId() const = 0;
+
enum Transition {
// Fade/unfade immediately.
TRANSITION_IMMEDIATE,
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 04b87d5..b18cae3 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -57,6 +57,7 @@
float mMinX, mMinY, mMaxX, mMaxY;
float mX, mY;
int32_t mButtonState;
+ int32_t mDisplayId;
protected:
virtual ~FakePointerController() { }
@@ -64,7 +65,7 @@
public:
FakePointerController() :
mHaveBounds(false), mMinX(0), mMinY(0), mMaxX(0), mMaxY(0), mX(0), mY(0),
- mButtonState(0) {
+ mButtonState(0), mDisplayId(ADISPLAY_ID_DEFAULT) {
}
void setBounds(float minX, float minY, float maxX, float maxY) {
@@ -75,6 +76,10 @@
mMaxY = maxY;
}
+ void setDisplayId(int32_t displayId) {
+ mDisplayId = displayId;
+ }
+
virtual void setPosition(float x, float y) {
mX = x;
mY = y;
@@ -93,6 +98,10 @@
*outY = mY;
}
+ virtual int32_t getDisplayId() const {
+ return mDisplayId;
+ }
+
private:
virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const {
*outMinX = mMinX;
@@ -262,6 +271,9 @@
virtual std::string getDeviceAlias(const InputDeviceIdentifier&) {
return "";
}
+
+ virtual void updatePointerDisplay() {
+ }
};
@@ -3127,6 +3139,30 @@
ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
}
+TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) {
+ CursorInputMapper* mapper = new CursorInputMapper(mDevice);
+ addMapperAndConfigure(mapper);
+
+ // Setup PointerController for second display.
+ constexpr int32_t SECOND_DISPLAY_ID = 1;
+ mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
+ mFakePointerController->setPosition(100, 200);
+ mFakePointerController->setButtonState(0);
+ mFakePointerController->setDisplayId(SECOND_DISPLAY_ID);
+
+ NotifyMotionArgs args;
+ process(mapper, ARBITRARY_TIME, EV_REL, REL_X, 10);
+ process(mapper, ARBITRARY_TIME, EV_REL, REL_Y, 20);
+ process(mapper, ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE, args.source);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
+ ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
+ 110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+ ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
+ ASSERT_EQ(SECOND_DISPLAY_ID, args.displayId);
+}
+
// --- TouchInputMapperTest ---
@@ -4625,7 +4661,6 @@
toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
}
-
// --- MultiTouchInputMapperTest ---
class MultiTouchInputMapperTest : public TouchInputMapperTest {
@@ -6246,4 +6281,30 @@
ASSERT_EQ(DISPLAY_ID, args.displayId);
}
+TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) {
+ // Setup PointerController for second display.
+ sp<FakePointerController> fakePointerController = new FakePointerController();
+ fakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
+ fakePointerController->setPosition(100, 200);
+ fakePointerController->setButtonState(0);
+ fakePointerController->setDisplayId(SECONDARY_DISPLAY_ID);
+ mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION);
+ addMapperAndConfigure(mapper);
+
+ // Check source is mouse that would obtain the PointerController.
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources());
+
+ NotifyMotionArgs motionArgs;
+ processPosition(mapper, 100, 100);
+ processSync(mapper);
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
+ ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
+}
+
} // namespace android