diff options
| author | 2024-05-23 18:02:54 +0000 | |
|---|---|---|
| committer | 2024-05-31 14:13:38 +0000 | |
| commit | bd49b28c7fccb17c4c402a66ff79dfab696fb9e6 (patch) | |
| tree | 16556e6ed1872f42978fad064c18bea03127a832 | |
| parent | 420d074de595faab93f711b3d7f411f13ba15a30 (diff) | |
Add Tests for PointerChoreographerDisplayInfoListener
This CL allowes DisplayInfoListener to be injected into
PointerChoreographer. This enables testing the logic inside the
listener.
Test: atest inputflinger_tests
Bug: 325252005
Change-Id: I0101119313070f9b0a4755398ea81ce1d0681faf
| -rw-r--r-- | services/inputflinger/PointerChoreographer.cpp | 48 | ||||
| -rw-r--r-- | services/inputflinger/PointerChoreographer.h | 20 | ||||
| -rw-r--r-- | services/inputflinger/tests/FakePointerController.cpp | 24 | ||||
| -rw-r--r-- | services/inputflinger/tests/FakePointerController.h | 6 | ||||
| -rw-r--r-- | services/inputflinger/tests/InterfaceMocks.h | 10 | ||||
| -rw-r--r-- | services/inputflinger/tests/PointerChoreographer_test.cpp | 314 |
6 files changed, 366 insertions, 56 deletions
diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp index 02453ef7a0..7d3a2df550 100644 --- a/services/inputflinger/PointerChoreographer.cpp +++ b/services/inputflinger/PointerChoreographer.cpp @@ -30,10 +30,6 @@ namespace android { -namespace input_flags = com::android::input::flags; -static const bool HIDE_TOUCH_INDICATORS_FOR_SECURE_WINDOWS = - input_flags::hide_pointer_indicators_for_secure_windows(); - namespace { bool isFromMouse(const NotifyMotionArgs& args) { @@ -106,8 +102,31 @@ std::unordered_set<ui::LogicalDisplayId> getPrivacySensitiveDisplaysFromWindowIn // --- PointerChoreographer --- -PointerChoreographer::PointerChoreographer(InputListenerInterface& listener, +PointerChoreographer::PointerChoreographer(InputListenerInterface& inputListener, PointerChoreographerPolicyInterface& policy) + : PointerChoreographer( + inputListener, policy, + [](const sp<android::gui::WindowInfosListener>& listener) { + auto initialInfo = std::make_pair(std::vector<android::gui::WindowInfo>{}, + std::vector<android::gui::DisplayInfo>{}); +#if defined(__ANDROID__) + SurfaceComposerClient::getDefault()->addWindowInfosListener(listener, + &initialInfo); +#endif + return initialInfo.first; + }, + [](const sp<android::gui::WindowInfosListener>& listener) { +#if defined(__ANDROID__) + SurfaceComposerClient::getDefault()->removeWindowInfosListener(listener); +#endif + }) { +} + +PointerChoreographer::PointerChoreographer( + android::InputListenerInterface& listener, + android::PointerChoreographerPolicyInterface& policy, + const android::PointerChoreographer::WindowListenerRegisterConsumer& registerListener, + const android::PointerChoreographer::WindowListenerUnregisterConsumer& unregisterListener) : mTouchControllerConstructor([this]() { return mPolicy.createPointerController( PointerControllerInterface::ControllerType::TOUCH); @@ -117,7 +136,9 @@ PointerChoreographer::PointerChoreographer(InputListenerInterface& listener, mDefaultMouseDisplayId(ui::LogicalDisplayId::DEFAULT), mNotifiedPointerDisplayId(ui::LogicalDisplayId::INVALID), mShowTouchesEnabled(false), - mStylusPointerIconEnabled(false) {} + mStylusPointerIconEnabled(false), + mRegisterListener(registerListener), + mUnregisterListener(unregisterListener) {} PointerChoreographer::~PointerChoreographer() { std::scoped_lock _l(mLock); @@ -125,6 +146,7 @@ PointerChoreographer::~PointerChoreographer() { return; } mWindowInfoListener->onPointerChoreographerDestroyed(); + mUnregisterListener(mWindowInfoListener); } void PointerChoreographer::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) { @@ -391,7 +413,7 @@ void PointerChoreographer::processDeviceReset(const NotifyDeviceResetArgs& args) } void PointerChoreographer::onControllerAddedOrRemovedLocked() { - if (!HIDE_TOUCH_INDICATORS_FOR_SECURE_WINDOWS) { + if (!com::android::input::flags::hide_pointer_indicators_for_secure_windows()) { return; } bool requireListener = !mTouchPointersByDevice.empty() || !mMousePointersByDisplay.empty() || @@ -399,18 +421,10 @@ void PointerChoreographer::onControllerAddedOrRemovedLocked() { if (requireListener && mWindowInfoListener == nullptr) { mWindowInfoListener = sp<PointerChoreographerDisplayInfoListener>::make(this); - auto initialInfo = std::make_pair(std::vector<android::gui::WindowInfo>{}, - std::vector<android::gui::DisplayInfo>{}); -#if defined(__ANDROID__) - SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener, - &initialInfo); -#endif - mWindowInfoListener->setInitialDisplayInfos(initialInfo.first); + mWindowInfoListener->setInitialDisplayInfos(mRegisterListener(mWindowInfoListener)); onPrivacySensitiveDisplaysChangedLocked(mWindowInfoListener->getPrivacySensitiveDisplays()); } else if (!requireListener && mWindowInfoListener != nullptr) { -#if defined(__ANDROID__) - SurfaceComposerClient::getDefault()->removeWindowInfosListener(mWindowInfoListener); -#endif + mUnregisterListener(mWindowInfoListener); mWindowInfoListener = nullptr; } else if (requireListener && mWindowInfoListener != nullptr) { // controller may have been added to an existing privacy sensitive display, we need to diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h index 11c5a0c6c7..d9b075f3ee 100644 --- a/services/inputflinger/PointerChoreographer.h +++ b/services/inputflinger/PointerChoreographer.h @@ -108,10 +108,6 @@ public: void notifyDeviceReset(const NotifyDeviceResetArgs& args) override; void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override; - // Public because it's also used by tests to simulate the WindowInfosListener callback - void onPrivacySensitiveDisplaysChanged( - const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays); - void dump(std::string& dump) override; private: @@ -139,6 +135,8 @@ private: void onPrivacySensitiveDisplaysChangedLocked( const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays) REQUIRES(mLock); + void onPrivacySensitiveDisplaysChanged( + const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays); /* This listener keeps tracks of visible privacy sensitive displays and updates the * choreographer if there are any changes. @@ -194,6 +192,20 @@ private: bool mShowTouchesEnabled GUARDED_BY(mLock); bool mStylusPointerIconEnabled GUARDED_BY(mLock); std::set<ui::LogicalDisplayId /*displayId*/> mDisplaysWithPointersHidden; + +protected: + using WindowListenerRegisterConsumer = std::function<std::vector<gui::WindowInfo>( + const sp<android::gui::WindowInfosListener>&)>; + using WindowListenerUnregisterConsumer = + std::function<void(const sp<android::gui::WindowInfosListener>&)>; + explicit PointerChoreographer(InputListenerInterface& listener, + PointerChoreographerPolicyInterface&, + const WindowListenerRegisterConsumer& registerListener, + const WindowListenerUnregisterConsumer& unregisterListener); + +private: + const WindowListenerRegisterConsumer mRegisterListener; + const WindowListenerUnregisterConsumer mUnregisterListener; }; } // namespace android diff --git a/services/inputflinger/tests/FakePointerController.cpp b/services/inputflinger/tests/FakePointerController.cpp index 456013e347..d0998ba851 100644 --- a/services/inputflinger/tests/FakePointerController.cpp +++ b/services/inputflinger/tests/FakePointerController.cpp @@ -77,10 +77,12 @@ void FakePointerController::setCustomPointerIcon(const SpriteIcon& icon) { } void FakePointerController::setSkipScreenshotFlagForDisplay(ui::LogicalDisplayId displayId) { + mDisplaysToSkipScreenshotFlagChanged = true; mDisplaysToSkipScreenshot.insert(displayId); } void FakePointerController::clearSkipScreenshotFlags() { + mDisplaysToSkipScreenshotFlagChanged = true; mDisplaysToSkipScreenshot.clear(); } @@ -125,13 +127,21 @@ void FakePointerController::assertCustomPointerIconNotSet() { ASSERT_EQ(std::nullopt, mCustomIconStyle); } -void FakePointerController::assertIsHiddenOnMirroredDisplays(ui::LogicalDisplayId displayId, - bool isHidden) { - if (isHidden) { - ASSERT_TRUE(mDisplaysToSkipScreenshot.find(displayId) != mDisplaysToSkipScreenshot.end()); - } else { - ASSERT_TRUE(mDisplaysToSkipScreenshot.find(displayId) == mDisplaysToSkipScreenshot.end()); - } +void FakePointerController::assertIsSkipScreenshotFlagSet(ui::LogicalDisplayId displayId) { + ASSERT_TRUE(mDisplaysToSkipScreenshot.find(displayId) != mDisplaysToSkipScreenshot.end()); +} + +void FakePointerController::assertIsSkipScreenshotFlagNotSet(ui::LogicalDisplayId displayId) { + ASSERT_TRUE(mDisplaysToSkipScreenshot.find(displayId) == mDisplaysToSkipScreenshot.end()); +} + +void FakePointerController::assertSkipScreenshotFlagChanged() { + ASSERT_TRUE(mDisplaysToSkipScreenshotFlagChanged); + mDisplaysToSkipScreenshotFlagChanged = false; +} + +void FakePointerController::assertSkipScreenshotFlagNotChanged() { + ASSERT_FALSE(mDisplaysToSkipScreenshotFlagChanged); } bool FakePointerController::isPointerShown() { diff --git a/services/inputflinger/tests/FakePointerController.h b/services/inputflinger/tests/FakePointerController.h index 8d95f65896..2c76c6214c 100644 --- a/services/inputflinger/tests/FakePointerController.h +++ b/services/inputflinger/tests/FakePointerController.h @@ -57,7 +57,10 @@ public: void assertPointerIconNotSet(); void assertCustomPointerIconSet(PointerIconStyle iconId); void assertCustomPointerIconNotSet(); - void assertIsHiddenOnMirroredDisplays(ui::LogicalDisplayId displayId, bool isHidden); + void assertIsSkipScreenshotFlagSet(ui::LogicalDisplayId displayId); + void assertIsSkipScreenshotFlagNotSet(ui::LogicalDisplayId displayId); + void assertSkipScreenshotFlagChanged(); + void assertSkipScreenshotFlagNotChanged(); bool isPointerShown(); private: @@ -81,6 +84,7 @@ private: std::map<ui::LogicalDisplayId, std::vector<int32_t>> mSpotsByDisplay; std::unordered_set<ui::LogicalDisplayId> mDisplaysToSkipScreenshot; + bool mDisplaysToSkipScreenshotFlagChanged{false}; }; } // namespace android diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h index 6389cdc5fb..6a35631e46 100644 --- a/services/inputflinger/tests/InterfaceMocks.h +++ b/services/inputflinger/tests/InterfaceMocks.h @@ -27,7 +27,9 @@ #include <EventHub.h> #include <InputReaderBase.h> +#include <InputReaderContext.h> #include <NotifyArgs.h> +#include <PointerChoreographerPolicyInterface.h> #include <StylusState.h> #include <VibrationElement.h> #include <android-base/logging.h> @@ -174,4 +176,12 @@ public: MOCK_METHOD(void, sysfsNodeChanged, (const std::string& sysfsNodePath), (override)); }; +class MockPointerChoreographerPolicyInterface : public PointerChoreographerPolicyInterface { +public: + MOCK_METHOD(std::shared_ptr<PointerControllerInterface>, createPointerController, + (PointerControllerInterface::ControllerType), (override)); + MOCK_METHOD(void, notifyPointerDisplayIdChanged, + (ui::LogicalDisplayId displayId, const FloatPoint& position), (override)); +}; + } // namespace android diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp index 69a7382cd4..b517928f66 100644 --- a/services/inputflinger/tests/PointerChoreographer_test.cpp +++ b/services/inputflinger/tests/PointerChoreographer_test.cpp @@ -22,6 +22,7 @@ #include <vector> #include "FakePointerController.h" +#include "InterfaceMocks.h" #include "NotifyArgsBuilders.h" #include "TestEventMatchers.h" #include "TestInputListener.h" @@ -89,10 +90,41 @@ static std::vector<DisplayViewport> createViewports(std::vector<ui::LogicalDispl // --- PointerChoreographerTest --- +class TestPointerChoreographer : public PointerChoreographer { +public: + TestPointerChoreographer(InputListenerInterface& inputListener, + PointerChoreographerPolicyInterface& policy, + sp<gui::WindowInfosListener>& windowInfoListener, + const std::vector<gui::WindowInfo>& mInitialWindowInfos); +}; + +TestPointerChoreographer::TestPointerChoreographer( + InputListenerInterface& inputListener, PointerChoreographerPolicyInterface& policy, + sp<gui::WindowInfosListener>& windowInfoListener, + const std::vector<gui::WindowInfo>& mInitialWindowInfos) + : PointerChoreographer( + inputListener, policy, + [&windowInfoListener, + &mInitialWindowInfos](const sp<android::gui::WindowInfosListener>& listener) { + windowInfoListener = listener; + return mInitialWindowInfos; + }, + [&windowInfoListener](const sp<android::gui::WindowInfosListener>& listener) { + windowInfoListener = nullptr; + }) {} + class PointerChoreographerTest : public testing::Test, public PointerChoreographerPolicyInterface { protected: TestInputListener mTestListener; - PointerChoreographer mChoreographer{mTestListener, *this}; + sp<gui::WindowInfosListener> mRegisteredWindowInfoListener; + std::vector<gui::WindowInfo> mInjectedInitialWindowInfos; + TestPointerChoreographer mChoreographer{mTestListener, *this, mRegisteredWindowInfoListener, + mInjectedInitialWindowInfos}; + + void SetUp() override { + // flag overrides + input_flags::hide_pointer_indicators_for_secure_windows(true); + } std::shared_ptr<FakePointerController> assertPointerControllerCreated( ControllerType expectedType) { @@ -131,6 +163,16 @@ protected: void assertPointerDisplayIdNotNotified() { ASSERT_EQ(std::nullopt, mPointerDisplayIdNotified); } + void assertWindowInfosListenerRegistered() { + ASSERT_NE(nullptr, mRegisteredWindowInfoListener) + << "WindowInfosListener was not registered"; + } + + void assertWindowInfosListenerNotRegistered() { + ASSERT_EQ(nullptr, mRegisteredWindowInfoListener) + << "WindowInfosListener was not unregistered"; + } + private: std::deque<std::pair<ControllerType, std::shared_ptr<FakePointerController>>> mCreatedControllers; @@ -1636,16 +1678,36 @@ TEST_F(PointerChoreographerTest, SetsPointerIconForMouseOnTwoDisplays) { firstMousePc->assertPointerIconNotSet(); } -using HidePointerForPrivacySensitiveDisplaysFixtureParam = +using SkipPointerScreenshotForPrivacySensitiveDisplaysFixtureParam = std::tuple<std::string_view /*name*/, uint32_t /*source*/, ControllerType, PointerBuilder, std::function<void(PointerChoreographer&)>, int32_t /*action*/>; -class HidePointerForPrivacySensitiveDisplaysTestFixture +class SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture : public PointerChoreographerTest, - public ::testing::WithParamInterface<HidePointerForPrivacySensitiveDisplaysFixtureParam> {}; + public ::testing::WithParamInterface< + SkipPointerScreenshotForPrivacySensitiveDisplaysFixtureParam> { +protected: + void initializePointerDevice(const PointerBuilder& pointerBuilder, const uint32_t source, + const std::function<void(PointerChoreographer&)> onControllerInit, + const int32_t action) { + mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); + + // Add appropriate pointer device + mChoreographer.notifyInputDevicesChanged( + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}}); + onControllerInit(mChoreographer); + + // Emit input events to create PointerController + mChoreographer.notifyMotion(MotionArgsBuilder(action, source) + .pointer(pointerBuilder) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + } +}; INSTANTIATE_TEST_SUITE_P( - PointerChoreographerTest, HidePointerForPrivacySensitiveDisplaysTestFixture, + PointerChoreographerTest, SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture, ::testing::Values( std::make_tuple( "TouchSpots", AINPUT_SOURCE_TOUCHSCREEN, ControllerType::TOUCH, @@ -1663,44 +1725,205 @@ INSTANTIATE_TEST_SUITE_P( "DrawingTablet", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS, ControllerType::MOUSE, STYLUS_POINTER, [](PointerChoreographer& pc) {}, AMOTION_EVENT_ACTION_HOVER_ENTER)), - [](const testing::TestParamInfo<HidePointerForPrivacySensitiveDisplaysFixtureParam>& p) { + [](const testing::TestParamInfo< + SkipPointerScreenshotForPrivacySensitiveDisplaysFixtureParam>& p) { return std::string{std::get<0>(p.param)}; }); -TEST_P(HidePointerForPrivacySensitiveDisplaysTestFixture, - HidesPointerOnMirroredDisplaysForPrivacySensitiveDisplay) { +TEST_P(SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture, + WindowInfosListenerIsOnlyRegisteredWhenRequired) { + const auto& [name, source, controllerType, pointerBuilder, onControllerInit, action] = + GetParam(); + assertWindowInfosListenerNotRegistered(); + + // Listener should registered when a pointer device is added + initializePointerDevice(pointerBuilder, source, onControllerInit, action); + assertWindowInfosListenerRegistered(); + + mChoreographer.notifyInputDevicesChanged({}); + assertWindowInfosListenerNotRegistered(); +} + +TEST_P(SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture, + InitialDisplayInfoIsPopulatedForListener) { + const auto& [name, source, controllerType, pointerBuilder, onControllerInit, action] = + GetParam(); + // listener should not be registered if there is no pointer device + assertWindowInfosListenerNotRegistered(); + + gui::WindowInfo windowInfo; + windowInfo.displayId = DISPLAY_ID; + windowInfo.inputConfig |= gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY; + mInjectedInitialWindowInfos = {windowInfo}; + + initializePointerDevice(pointerBuilder, source, onControllerInit, action); + assertWindowInfosListenerRegistered(); + + // Pointer indicators should be hidden based on the initial display info + auto pc = assertPointerControllerCreated(controllerType); + pc->assertIsSkipScreenshotFlagSet(DISPLAY_ID); + pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID); + + // un-marking the privacy sensitive display should reset the state + windowInfo.inputConfig.clear(); + gui::DisplayInfo displayInfo; + displayInfo.displayId = DISPLAY_ID; + mRegisteredWindowInfoListener + ->onWindowInfosChanged(/*windowInfosUpdate=*/ + {{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0}); + + pc->assertIsSkipScreenshotFlagNotSet(DISPLAY_ID); + pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID); +} + +TEST_P(SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture, + SkipsPointerScreenshotForPrivacySensitiveWindows) { + const auto& [name, source, controllerType, pointerBuilder, onControllerInit, action] = + GetParam(); + initializePointerDevice(pointerBuilder, source, onControllerInit, action); + + // By default pointer indicators should not be hidden + auto pc = assertPointerControllerCreated(controllerType); + pc->assertIsSkipScreenshotFlagNotSet(DISPLAY_ID); + pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID); + + // marking a display privacy sensitive should set flag to hide pointer indicators on the + // display screenshot + gui::WindowInfo windowInfo; + windowInfo.displayId = DISPLAY_ID; + windowInfo.inputConfig |= gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY; + gui::DisplayInfo displayInfo; + displayInfo.displayId = DISPLAY_ID; + assertWindowInfosListenerRegistered(); + mRegisteredWindowInfoListener + ->onWindowInfosChanged(/*windowInfosUpdate=*/ + {{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0}); + + pc->assertIsSkipScreenshotFlagSet(DISPLAY_ID); + pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID); + + // un-marking the privacy sensitive display should reset the state + windowInfo.inputConfig.clear(); + mRegisteredWindowInfoListener + ->onWindowInfosChanged(/*windowInfosUpdate=*/ + {{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0}); + + pc->assertIsSkipScreenshotFlagNotSet(DISPLAY_ID); + pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID); +} + +TEST_P(SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture, + DoesNotSkipPointerScreenshotForHiddenPrivacySensitiveWindows) { const auto& [name, source, controllerType, pointerBuilder, onControllerInit, action] = GetParam(); - input_flags::hide_pointer_indicators_for_secure_windows(true); + initializePointerDevice(pointerBuilder, source, onControllerInit, action); + + // By default pointer indicators should not be hidden + auto pc = assertPointerControllerCreated(controllerType); + pc->assertIsSkipScreenshotFlagNotSet(DISPLAY_ID); + pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID); + + gui::WindowInfo windowInfo; + windowInfo.displayId = DISPLAY_ID; + windowInfo.inputConfig |= gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY; + windowInfo.inputConfig |= gui::WindowInfo::InputConfig::NOT_VISIBLE; + gui::DisplayInfo displayInfo; + displayInfo.displayId = DISPLAY_ID; + assertWindowInfosListenerRegistered(); + mRegisteredWindowInfoListener + ->onWindowInfosChanged(/*windowInfosUpdate=*/ + {{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0}); + + pc->assertIsSkipScreenshotFlagNotSet(DISPLAY_ID); + pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID); +} + +TEST_P(SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture, + DoesNotUpdateControllerForUnchangedPrivacySensitiveWindows) { + const auto& [name, source, controllerType, pointerBuilder, onControllerInit, action] = + GetParam(); + initializePointerDevice(pointerBuilder, source, onControllerInit, action); + + auto pc = assertPointerControllerCreated(controllerType); + gui::WindowInfo windowInfo; + windowInfo.displayId = DISPLAY_ID; + windowInfo.inputConfig |= gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY; + gui::DisplayInfo displayInfo; + displayInfo.displayId = DISPLAY_ID; + assertWindowInfosListenerRegistered(); + mRegisteredWindowInfoListener + ->onWindowInfosChanged(/*windowInfosUpdate=*/ + {{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0}); + + gui::WindowInfo windowInfo2 = windowInfo; + windowInfo2.inputConfig.clear(); + pc->assertSkipScreenshotFlagChanged(); + + // controller should not be updated if there are no changes in privacy sensitive windows + mRegisteredWindowInfoListener->onWindowInfosChanged(/*windowInfosUpdate=*/ + {{windowInfo, windowInfo2}, + {displayInfo}, + /*vsyncId=*/0, + /*timestamp=*/0}); + pc->assertSkipScreenshotFlagNotChanged(); +} + +TEST_F_WITH_FLAGS( + PointerChoreographerTest, HidesPointerScreenshotForExistingPrivacySensitiveWindows, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, + hide_pointer_indicators_for_secure_windows))) { mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); - // Add appropriate pointer device + // Add a first mouse device mChoreographer.notifyInputDevicesChanged( - {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}}); - onControllerInit(mChoreographer); + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, DISPLAY_ID)}}); - // Emit input events to create PointerController - mChoreographer.notifyMotion(MotionArgsBuilder(action, source) - .pointer(pointerBuilder) + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) + .pointer(MOUSE_POINTER) .deviceId(DEVICE_ID) .displayId(DISPLAY_ID) .build()); - // By default pointer indicators should not be hidden - auto pc = assertPointerControllerCreated(controllerType); - pc->assertIsHiddenOnMirroredDisplays(DISPLAY_ID, /*isHidden=*/false); - pc->assertIsHiddenOnMirroredDisplays(ANOTHER_DISPLAY_ID, /*isHidden=*/false); + gui::WindowInfo windowInfo; + windowInfo.displayId = DISPLAY_ID; + windowInfo.inputConfig |= gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY; + gui::DisplayInfo displayInfo; + displayInfo.displayId = DISPLAY_ID; + assertWindowInfosListenerRegistered(); + mRegisteredWindowInfoListener + ->onWindowInfosChanged(/*windowInfosUpdate=*/ + {{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0}); - // marking a display privacy sensitive should set flag to hide pointer indicators on the - // corresponding mirrored display - mChoreographer.onPrivacySensitiveDisplaysChanged(/*privacySensitiveDisplays=*/{DISPLAY_ID}); - pc->assertIsHiddenOnMirroredDisplays(DISPLAY_ID, /*isHidden=*/true); - pc->assertIsHiddenOnMirroredDisplays(ANOTHER_DISPLAY_ID, /*isHidden=*/false); + auto pc = assertPointerControllerCreated(ControllerType::MOUSE); + pc->assertIsSkipScreenshotFlagSet(DISPLAY_ID); + pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID); + + // Add a second touch device and controller + mChoreographer.notifyInputDevicesChanged( + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID)}}); + mChoreographer.setShowTouchesEnabled(true); + mChoreographer.notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(FIRST_TOUCH_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + + // Pointer indicators should be hidden for this controller by default + auto pc2 = assertPointerControllerCreated(ControllerType::TOUCH); + pc->assertIsSkipScreenshotFlagSet(DISPLAY_ID); + pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID); // un-marking the privacy sensitive display should reset the state - mChoreographer.onPrivacySensitiveDisplaysChanged(/*privacySensitiveDisplays=*/{}); - pc->assertIsHiddenOnMirroredDisplays(DISPLAY_ID, /*isHidden=*/false); - pc->assertIsHiddenOnMirroredDisplays(ANOTHER_DISPLAY_ID, /*isHidden=*/false); + windowInfo.inputConfig.clear(); + mRegisteredWindowInfoListener + ->onWindowInfosChanged(/*windowInfosUpdate=*/ + {{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0}); + + pc->assertIsSkipScreenshotFlagNotSet(DISPLAY_ID); + pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID); + pc2->assertIsSkipScreenshotFlagNotSet(DISPLAY_ID); + pc2->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID); } TEST_P(StylusTestFixture, SetsPointerIconForStylus) { @@ -2070,4 +2293,41 @@ TEST_F(PointerChoreographerTest, MouseAndDrawingTabletReportMouseEvents) { assertPointerControllerRemoved(pc); } +class PointerChoreographerWindowInfoListenerTest : public testing::Test {}; + +TEST_F_WITH_FLAGS( + PointerChoreographerWindowInfoListenerTest, + doesNotCrashIfListenerCalledAfterPointerChoreographerDestroyed, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, + hide_pointer_indicators_for_secure_windows))) { + sp<android::gui::WindowInfosListener> registeredListener; + sp<android::gui::WindowInfosListener> localListenerCopy; + { + testing::NiceMock<MockPointerChoreographerPolicyInterface> mockPolicy; + EXPECT_CALL(mockPolicy, createPointerController(ControllerType::MOUSE)) + .WillOnce(testing::Return(std::make_shared<FakePointerController>())); + TestInputListener testListener; + std::vector<gui::WindowInfo> injectedInitialWindowInfos; + TestPointerChoreographer testChoreographer{testListener, mockPolicy, registeredListener, + injectedInitialWindowInfos}; + testChoreographer.setDisplayViewports(createViewports({DISPLAY_ID})); + + // Add mouse to create controller and listener + testChoreographer.notifyInputDevicesChanged( + {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, DISPLAY_ID)}}); + + ASSERT_NE(nullptr, registeredListener) << "WindowInfosListener was not registered"; + localListenerCopy = registeredListener; + } + ASSERT_EQ(nullptr, registeredListener) << "WindowInfosListener was not unregistered"; + + gui::WindowInfo windowInfo; + windowInfo.displayId = DISPLAY_ID; + windowInfo.inputConfig |= gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY; + gui::DisplayInfo displayInfo; + displayInfo.displayId = DISPLAY_ID; + localListenerCopy->onWindowInfosChanged( + /*windowInfosUpdate=*/{{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0}); +} + } // namespace android |