Move occlusion detection into logical space
Same as our "hit test" to find the target window, since WM works in
logical space, we consider the window's frame to be (l, t, r, b), and
the portion of the window that can be occluded in the x-direction is
[l, r), and the portion of the window that can be occluded in the
y-direction is [t, b). When the logical space is different from the
physical space, the opening and closing intervals in each of these
directions will be inconsistent, leading to abnormal detection of the
edge part. Here we move the occlusion detection to the logical
space as well, consistent with the "hit test" for finding the target
window.
Bug: 327712879
Test: atest inputflinger_tests
Test: Create a window that can cause occlusion and perform clicks on the edges, making sure that the occlusion range is x = [l, r), y = [t, b) under each direction of the screen.
Signed-off-by: Linnan Li <lilinnan@xiaomi.corp-partner.google.com>
(cherry picked from https://partner-android-review.googlesource.com/q/commit:1a0060e9bcd25bee6ce7a9f5d01b9446b0c4d73b)
Merged-In: I19b739bc8f1e48d8bc70020a2b07da227eaa6d8b
Change-Id: I19b739bc8f1e48d8bc70020a2b07da227eaa6d8b
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index f0f4d93..621d9ea 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -5361,6 +5361,94 @@
window->assertNoEvents();
}
+// This test verifies the occlusion detection for all rotations of the display by tapping
+// in different locations on the display, specifically points close to the four corners of a
+// window.
+TEST_P(InputDispatcherDisplayOrientationFixture, BlockUntrustClickInDifferentOrientations) {
+ constexpr static int32_t displayWidth = 400;
+ constexpr static int32_t displayHeight = 800;
+
+ std::shared_ptr<FakeApplicationHandle> untrustedWindowApplication =
+ std::make_shared<FakeApplicationHandle>();
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+ const auto rotation = GetParam();
+
+ // Set up the display with the specified rotation.
+ const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
+ const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
+ const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
+ const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
+ logicalDisplayWidth, logicalDisplayHeight);
+ addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
+
+ // Create a window that not trusted.
+ const Rect untrustedWindowFrameInLogicalDisplay(100, 100, 200, 300);
+
+ const Rect untrustedWindowFrameInDisplay =
+ displayTransform.inverse().transform(untrustedWindowFrameInLogicalDisplay);
+
+ sp<FakeWindowHandle> untrustedWindow =
+ sp<FakeWindowHandle>::make(untrustedWindowApplication, mDispatcher, "UntrustedWindow",
+ ADISPLAY_ID_DEFAULT);
+ untrustedWindow->setFrame(untrustedWindowFrameInDisplay, displayTransform);
+ untrustedWindow->setTrustedOverlay(false);
+ untrustedWindow->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
+ untrustedWindow->setTouchable(false);
+ untrustedWindow->setAlpha(1.0f);
+ untrustedWindow->setOwnerInfo(gui::Pid{1}, gui::Uid{101});
+ addWindow(untrustedWindow);
+
+ // Create a simple app window below the untrusted window.
+ const Rect simpleAppWindowFrameInLogicalDisplay(0, 0, 300, 600);
+ const Rect simpleAppWindowFrameInDisplay =
+ displayTransform.inverse().transform(simpleAppWindowFrameInLogicalDisplay);
+
+ sp<FakeWindowHandle> simpleAppWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "SimpleAppWindow",
+ ADISPLAY_ID_DEFAULT);
+ simpleAppWindow->setFrame(simpleAppWindowFrameInDisplay, displayTransform);
+ simpleAppWindow->setOwnerInfo(gui::Pid{2}, gui::Uid{202});
+ addWindow(simpleAppWindow);
+
+ // The following points in logical display space should be inside the untrusted window, so
+ // the simple window could not receive events that coordinate is these point.
+ static const std::array<vec2, 4> untrustedPoints{
+ {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
+
+ for (const auto untrustedPoint : untrustedPoints) {
+ const vec2 p = displayTransform.inverse().transform(untrustedPoint);
+ const PointF pointInDisplaySpace{p.x, p.y};
+ mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {pointInDisplaySpace}));
+ mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {pointInDisplaySpace}));
+ }
+ untrustedWindow->assertNoEvents();
+ simpleAppWindow->assertNoEvents();
+ // The following points in logical display space should be outside the untrusted window, so
+ // the simple window should receive events that coordinate is these point.
+ static const std::array<vec2, 5> trustedPoints{
+ {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
+ for (const auto trustedPoint : trustedPoints) {
+ const vec2 p = displayTransform.inverse().transform(trustedPoint);
+ const PointF pointInDisplaySpace{p.x, p.y};
+ mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {pointInDisplaySpace}));
+ simpleAppWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
+ AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
+ mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {pointInDisplaySpace}));
+ simpleAppWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT,
+ AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
+ }
+ untrustedWindow->assertNoEvents();
+}
+
// Run the precision tests for all rotations.
INSTANTIATE_TEST_SUITE_P(InputDispatcherDisplayOrientationTests,
InputDispatcherDisplayOrientationFixture,