@@ -1923,6 +1923,99 @@ TEST_F(InputDispatcherTest, HoverMoveAndScroll) {
19231923 window->consumeMotionEvent(WithMotionAction(ACTION_SCROLL));
19241924}
19251925
1926+ /**
1927+ * Two windows: a trusted overlay and a regular window underneath. Both windows are visible.
1928+ * Mouse is hovered, and the hover event should only go to the overlay.
1929+ * However, next, the touchable region of the trusted overlay shrinks. The mouse position hasn't
1930+ * changed, but the cursor would now end up hovering above the regular window underneatch.
1931+ * If the mouse is now clicked, this would generate an ACTION_DOWN event, which would go to the
1932+ * regular window. However, the trusted overlay is also watching for outside touch.
1933+ * The trusted overlay should get two events:
1934+ * 1) The ACTION_OUTSIDE event, since the click is now not inside its touchable region
1935+ * 2) The HOVER_EXIT event, since the mouse pointer is no longer hovering inside this window
1936+ *
1937+ * This test reproduces a crash where there is an overlap between dispatch modes for the trusted
1938+ * overlay touch target, since the event is causing both an ACTION_OUTSIDE, and as a HOVER_EXIT.
1939+ */
1940+ TEST_F(InputDispatcherTest, MouseClickUnderShrinkingTrustedOverlay) {
1941+ std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
1942+ sp<FakeWindowHandle> overlay = sp<FakeWindowHandle>::make(app, mDispatcher, "Trusted overlay",
1943+ ui::LogicalDisplayId::DEFAULT);
1944+ overlay->setTrustedOverlay(true);
1945+ overlay->setWatchOutsideTouch(true);
1946+ overlay->setFrame(Rect(0, 0, 200, 200));
1947+
1948+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(app, mDispatcher, "Regular window",
1949+ ui::LogicalDisplayId::DEFAULT);
1950+ window->setFrame(Rect(0, 0, 200, 200));
1951+
1952+ mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
1953+ // Hover the mouse into the overlay
1954+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1955+ .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1956+ .build());
1957+ overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
1958+
1959+ // Now, shrink the touchable region of the overlay! This will cause the cursor to suddenly have
1960+ // the regular window as the touch target
1961+ overlay->setTouchableRegion(Region({0, 0, 0, 0}));
1962+ mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
1963+
1964+ // Now we can click with the mouse. The click should go into the regular window
1965+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
1966+ .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
1967+ .build());
1968+ overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
1969+ overlay->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE));
1970+ window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
1971+ }
1972+
1973+ /**
1974+ * Similar to above, but also has a spy on top that also catches the HOVER
1975+ * events. Also, instead of ACTION_DOWN, we are continuing to send the hovering
1976+ * stream to ensure that the spy receives hover events correctly.
1977+ */
1978+ TEST_F(InputDispatcherTest, MouseClickUnderShrinkingTrustedOverlayWithSpy) {
1979+ std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
1980+ sp<FakeWindowHandle> spyWindow =
1981+ sp<FakeWindowHandle>::make(app, mDispatcher, "Spy", ui::LogicalDisplayId::DEFAULT);
1982+ spyWindow->setFrame(Rect(0, 0, 200, 200));
1983+ spyWindow->setTrustedOverlay(true);
1984+ spyWindow->setSpy(true);
1985+ sp<FakeWindowHandle> overlay = sp<FakeWindowHandle>::make(app, mDispatcher, "Trusted overlay",
1986+ ui::LogicalDisplayId::DEFAULT);
1987+ overlay->setTrustedOverlay(true);
1988+ overlay->setWatchOutsideTouch(true);
1989+ overlay->setFrame(Rect(0, 0, 200, 200));
1990+
1991+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(app, mDispatcher, "Regular window",
1992+ ui::LogicalDisplayId::DEFAULT);
1993+ window->setFrame(Rect(0, 0, 200, 200));
1994+
1995+ mDispatcher->onWindowInfosChanged(
1996+ {{*spyWindow->getInfo(), *overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
1997+ // Hover the mouse into the overlay
1998+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1999+ .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
2000+ .build());
2001+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2002+ overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2003+
2004+ // Now, shrink the touchable region of the overlay! This will cause the cursor to suddenly have
2005+ // the regular window as the touch target
2006+ overlay->setTouchableRegion(Region({0, 0, 0, 0}));
2007+ mDispatcher->onWindowInfosChanged(
2008+ {{*spyWindow->getInfo(), *overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
2009+
2010+ // Now we can click with the mouse. The click should go into the regular window
2011+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
2012+ .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
2013+ .build());
2014+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
2015+ overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
2016+ window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
2017+ }
2018+
19262019using InputDispatcherMultiDeviceTest = InputDispatcherTest;
19272020
19282021/**
0 commit comments