Add setPointerIcon for PointerChoreographer
To set pointer icon for mouse or stylus, we are going to use
setPointerIcon with more parameters which will be useful for
multi-device experience and security.
Test: atest inputflinger_tests
Bug: 293587049
Change-Id: Ie0250928ed28c6dc238faa8dcae8ad154ed053fe
diff --git a/services/inputflinger/tests/FakePointerController.cpp b/services/inputflinger/tests/FakePointerController.cpp
index 8043812..80319f2 100644
--- a/services/inputflinger/tests/FakePointerController.cpp
+++ b/services/inputflinger/tests/FakePointerController.cpp
@@ -54,6 +54,16 @@
viewport.logicalBottom - 1);
}
+void FakePointerController::updatePointerIcon(PointerIconStyle iconId) {
+ ASSERT_FALSE(mIconStyle.has_value()) << "Pointer icon was set more than once";
+ mIconStyle = iconId;
+}
+
+void FakePointerController::setCustomPointerIcon(const SpriteIcon& icon) {
+ ASSERT_FALSE(mCustomIconStyle.has_value()) << "Custom pointer icon was set more than once";
+ mCustomIconStyle = icon.style;
+}
+
void FakePointerController::assertViewportSet(int32_t displayId) {
ASSERT_TRUE(mDisplayId);
ASSERT_EQ(displayId, mDisplayId);
@@ -75,6 +85,26 @@
ASSERT_EQ(static_cast<size_t>(count), it->second.size());
}
+void FakePointerController::assertPointerIconSet(PointerIconStyle iconId) {
+ ASSERT_TRUE(mIconStyle) << "Pointer icon style was not set";
+ ASSERT_EQ(iconId, mIconStyle);
+ mIconStyle.reset();
+}
+
+void FakePointerController::assertPointerIconNotSet() {
+ ASSERT_EQ(std::nullopt, mIconStyle);
+}
+
+void FakePointerController::assertCustomPointerIconSet(PointerIconStyle iconId) {
+ ASSERT_TRUE(mCustomIconStyle) << "Custom pointer icon was not set";
+ ASSERT_EQ(iconId, mCustomIconStyle);
+ mCustomIconStyle.reset();
+}
+
+void FakePointerController::assertCustomPointerIconNotSet() {
+ ASSERT_EQ(std::nullopt, mCustomIconStyle);
+}
+
bool FakePointerController::isPointerShown() {
return mIsPointerShown;
}
diff --git a/services/inputflinger/tests/FakePointerController.h b/services/inputflinger/tests/FakePointerController.h
index 9be6a6c..7668011 100644
--- a/services/inputflinger/tests/FakePointerController.h
+++ b/services/inputflinger/tests/FakePointerController.h
@@ -24,6 +24,10 @@
namespace android {
+struct SpriteIcon {
+ PointerIconStyle style;
+};
+
class FakePointerController : public PointerControllerInterface {
public:
virtual ~FakePointerController() {}
@@ -35,11 +39,17 @@
FloatPoint getPosition() const override;
int32_t getDisplayId() const override;
void setDisplayViewport(const DisplayViewport& viewport) override;
+ void updatePointerIcon(PointerIconStyle iconId) override;
+ void setCustomPointerIcon(const SpriteIcon& icon) override;
void assertViewportSet(int32_t displayId);
void assertViewportNotSet();
void assertPosition(float x, float y);
void assertSpotCount(int32_t displayId, int32_t count);
+ void assertPointerIconSet(PointerIconStyle iconId);
+ void assertPointerIconNotSet();
+ void assertCustomPointerIconSet(PointerIconStyle iconId);
+ void assertCustomPointerIconNotSet();
bool isPointerShown();
private:
@@ -58,6 +68,8 @@
float mX{0}, mY{0};
std::optional<int32_t> mDisplayId;
bool mIsPointerShown{false};
+ std::optional<PointerIconStyle> mIconStyle;
+ std::optional<PointerIconStyle> mCustomIconStyle;
std::map<int32_t, std::vector<int32_t>> mSpotsByDisplay;
};
diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp
index 1efb797..2457f7c 100644
--- a/services/inputflinger/tests/PointerChoreographer_test.cpp
+++ b/services/inputflinger/tests/PointerChoreographer_test.cpp
@@ -1511,4 +1511,278 @@
ASSERT_FALSE(pc->isPointerShown());
}
+TEST_F(PointerChoreographerTest, SetsPointerIconForMouse) {
+ // Make sure there is a PointerController.
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE)}});
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(ADISPLAY_ID_NONE)
+ .build());
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertPointerIconNotSet();
+
+ // Set pointer icon for the device.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
+ pc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+}
+
+TEST_F(PointerChoreographerTest, DoesNotSetMousePointerIconForWrongDisplayId) {
+ // Make sure there is a PointerController.
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE)}});
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(ADISPLAY_ID_NONE)
+ .build());
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertPointerIconNotSet();
+
+ // Set pointer icon for wrong display id. This should be ignored.
+ ASSERT_FALSE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, ANOTHER_DISPLAY_ID,
+ SECOND_DEVICE_ID));
+ pc->assertPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, DoesNotSetPointerIconForWrongDeviceId) {
+ // Make sure there is a PointerController.
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE)}});
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(ADISPLAY_ID_NONE)
+ .build());
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertPointerIconNotSet();
+
+ // Set pointer icon for wrong device id. This should be ignored.
+ ASSERT_FALSE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID,
+ SECOND_DEVICE_ID));
+ pc->assertPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, DoesNotSetPointerIconForDeviceWithoutPointerController) {
+ // Add two devices, one with a PointerController and the other without PointerController.
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE),
+ generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE, ANOTHER_DISPLAY_ID)}});
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(ADISPLAY_ID_NONE)
+ .build());
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertPointerIconNotSet();
+
+ // Set pointer icon for the device without PointerController. This should be ignored.
+ ASSERT_FALSE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, ANOTHER_DISPLAY_ID,
+ SECOND_DEVICE_ID));
+ pc->assertPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, SetsCustomPointerIconForMouse) {
+ // Make sure there is a PointerController.
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE)}});
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(ADISPLAY_ID_NONE)
+ .build());
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertCustomPointerIconNotSet();
+
+ // Set custom pointer icon for the device.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(std::make_unique<SpriteIcon>(
+ PointerIconStyle::TYPE_CUSTOM),
+ DISPLAY_ID, DEVICE_ID));
+ pc->assertCustomPointerIconSet(PointerIconStyle::TYPE_CUSTOM);
+
+ // Set custom pointer icon for wrong device id. This should be ignored.
+ ASSERT_FALSE(mChoreographer.setPointerIcon(std::make_unique<SpriteIcon>(
+ PointerIconStyle::TYPE_CUSTOM),
+ DISPLAY_ID, SECOND_DEVICE_ID));
+ pc->assertCustomPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, SetsPointerIconForMouseOnTwoDisplays) {
+ // Make sure there are two PointerControllers on different displays.
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE),
+ generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE, ANOTHER_DISPLAY_ID)}});
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(ADISPLAY_ID_NONE)
+ .build());
+ auto firstMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
+ ASSERT_EQ(DISPLAY_ID, firstMousePc->getDisplayId());
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(SECOND_DEVICE_ID)
+ .displayId(ANOTHER_DISPLAY_ID)
+ .build());
+ auto secondMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
+ ASSERT_EQ(ANOTHER_DISPLAY_ID, secondMousePc->getDisplayId());
+
+ // Set pointer icon for one mouse.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
+ firstMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+ secondMousePc->assertPointerIconNotSet();
+
+ // Set pointer icon for another mouse.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, ANOTHER_DISPLAY_ID,
+ SECOND_DEVICE_ID));
+ secondMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+ firstMousePc->assertPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, SetsPointerIconForStylus) {
+ // Make sure there is a PointerController.
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}});
+ mChoreographer.setStylusPointerIconEnabled(true);
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ auto pc = assertPointerControllerCreated(ControllerType::STYLUS);
+ pc->assertPointerIconNotSet();
+
+ // Set pointer icon for the device.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
+ pc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+
+ // Set pointer icon for wrong device id. This should be ignored.
+ ASSERT_FALSE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID,
+ SECOND_DEVICE_ID));
+ pc->assertPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, SetsCustomPointerIconForStylus) {
+ // Make sure there is a PointerController.
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}});
+ mChoreographer.setStylusPointerIconEnabled(true);
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ auto pc = assertPointerControllerCreated(ControllerType::STYLUS);
+ pc->assertCustomPointerIconNotSet();
+
+ // Set custom pointer icon for the device.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(std::make_unique<SpriteIcon>(
+ PointerIconStyle::TYPE_CUSTOM),
+ DISPLAY_ID, DEVICE_ID));
+ pc->assertCustomPointerIconSet(PointerIconStyle::TYPE_CUSTOM);
+
+ // Set custom pointer icon for wrong device id. This should be ignored.
+ ASSERT_FALSE(mChoreographer.setPointerIcon(std::make_unique<SpriteIcon>(
+ PointerIconStyle::TYPE_CUSTOM),
+ DISPLAY_ID, SECOND_DEVICE_ID));
+ pc->assertCustomPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, SetsPointerIconForTwoStyluses) {
+ // Make sure there are two StylusPointerControllers. They can be on a same display.
+ mChoreographer.setStylusPointerIconEnabled(true);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID),
+ generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}});
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ auto firstStylusPc = assertPointerControllerCreated(ControllerType::STYLUS);
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(SECOND_DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ auto secondStylusPc = assertPointerControllerCreated(ControllerType::STYLUS);
+
+ // Set pointer icon for one stylus.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
+ firstStylusPc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+ secondStylusPc->assertPointerIconNotSet();
+
+ // Set pointer icon for another stylus.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID,
+ SECOND_DEVICE_ID));
+ secondStylusPc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+ firstStylusPc->assertPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, SetsPointerIconForMouseAndStylus) {
+ // Make sure there are PointerControllers for a mouse and a stylus.
+ mChoreographer.setStylusPointerIconEnabled(true);
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE),
+ generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}});
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(ADISPLAY_ID_NONE)
+ .build());
+ auto mousePc = assertPointerControllerCreated(ControllerType::MOUSE);
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(SECOND_DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ auto stylusPc = assertPointerControllerCreated(ControllerType::STYLUS);
+
+ // Set pointer icon for the mouse.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
+ mousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+ stylusPc->assertPointerIconNotSet();
+
+ // Set pointer icon for the stylus.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID,
+ SECOND_DEVICE_ID));
+ stylusPc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+ mousePc->assertPointerIconNotSet();
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index 2f84497..81c570d 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -275,6 +275,8 @@
void clearSpots() override {}
int32_t getDisplayId() const override { return mFdp->ConsumeIntegral<int32_t>(); }
void setDisplayViewport(const DisplayViewport& displayViewport) override {}
+ void updatePointerIcon(PointerIconStyle iconId) override {}
+ void setCustomPointerIcon(const SpriteIcon& icon) override {}
std::string dump() override { return ""; }
};