summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Linnan Li <lilinnan@xiaomi.corp-partner.google.com> 2024-03-05 14:43:05 +0000
committer Cherrypicker Worker <android-build-cherrypicker-worker@google.com> 2024-03-05 14:43:05 +0000
commit5e5645e860048bcdfef5db01b936e73357174caf (patch)
tree10532d531add31ec7ad698d7e195c7e85d365998
parentd26c9194865433ff01584921f17339e8a719c34a (diff)
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
-rw-r--r--libs/gui/WindowInfo.cpp8
-rw-r--r--libs/gui/include/gui/WindowInfo.h4
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp21
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.h4
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp88
5 files changed, 107 insertions, 18 deletions
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index 86bf0ee745..ad0d99d11e 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -73,14 +73,6 @@ void WindowInfo::addTouchableRegion(const Rect& region) {
touchableRegion.orSelf(region);
}
-bool WindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
- return touchableRegion.contains(x, y);
-}
-
-bool WindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
- return x >= frame.left && x < frame.right && y >= frame.top && y < frame.bottom;
-}
-
bool WindowInfo::supportsSplitTouch() const {
return !inputConfig.test(InputConfig::PREVENT_SPLITTING);
}
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 32d60be612..2d1b51a418 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -254,10 +254,6 @@ struct WindowInfo : public Parcelable {
void addTouchableRegion(const Rect& region);
- bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
-
- bool frameContainsPoint(int32_t x, int32_t y) const;
-
bool supportsSplitTouch() const;
bool isSpy() const;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 7f54bf1945..55976137c5 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -573,6 +573,18 @@ bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, float
return true;
}
+// Returns true if the given window's frame can occlude pointer events at the given display
+// location.
+bool windowOccludesTouchAt(const WindowInfo& windowInfo, int displayId, float x, float y,
+ const ui::Transform& displayTransform) {
+ if (windowInfo.displayId != displayId) {
+ return false;
+ }
+ const auto frame = displayTransform.transform(windowInfo.frame);
+ const auto p = floor(displayTransform.transform(x, y));
+ return p.x >= frame.left && p.x < frame.right && p.y >= frame.top && p.y < frame.bottom;
+}
+
bool isPointerFromStylus(const MotionEntry& entry, int32_t pointerIndex) {
return isFromSource(entry.source, AINPUT_SOURCE_STYLUS) &&
isStylusToolType(entry.pointerProperties[pointerIndex].toolType);
@@ -3056,7 +3068,7 @@ static bool canBeObscuredBy(const sp<WindowInfoHandle>& windowHandle,
* If neither of those is true, then it means the touch can be allowed.
*/
InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLocked(
- const sp<WindowInfoHandle>& windowHandle, int32_t x, int32_t y) const {
+ const sp<WindowInfoHandle>& windowHandle, float x, float y) const {
const WindowInfo* windowInfo = windowHandle->getInfo();
int32_t displayId = windowInfo->displayId;
const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
@@ -3070,7 +3082,8 @@ InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLo
break; // All future windows are below us. Exit early.
}
const WindowInfo* otherInfo = otherHandle->getInfo();
- if (canBeObscuredBy(windowHandle, otherHandle) && otherInfo->frameContainsPoint(x, y) &&
+ if (canBeObscuredBy(windowHandle, otherHandle) &&
+ windowOccludesTouchAt(*otherInfo, displayId, x, y, getTransformLocked(displayId)) &&
!haveSameApplicationToken(windowInfo, otherInfo)) {
if (DEBUG_TOUCH_OCCLUSION) {
info.debugInfo.push_back(
@@ -3140,7 +3153,7 @@ bool InputDispatcher::isTouchTrustedLocked(const TouchOcclusionInfo& occlusionIn
}
bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<WindowInfoHandle>& windowHandle,
- int32_t x, int32_t y) const {
+ float x, float y) const {
int32_t displayId = windowHandle->getInfo()->displayId;
const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
for (const sp<WindowInfoHandle>& otherHandle : windowHandles) {
@@ -3149,7 +3162,7 @@ bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<WindowInfoHandle>&
}
const WindowInfo* otherInfo = otherHandle->getInfo();
if (canBeObscuredBy(windowHandle, otherHandle) &&
- otherInfo->frameContainsPoint(x, y)) {
+ windowOccludesTouchAt(*otherInfo, displayId, x, y, getTransformLocked(displayId))) {
return true;
}
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 269bfddb8c..9c8d5889d1 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -565,11 +565,11 @@ private:
};
TouchOcclusionInfo computeTouchOcclusionInfoLocked(
- const sp<android::gui::WindowInfoHandle>& windowHandle, int32_t x, int32_t y) const
+ const sp<android::gui::WindowInfoHandle>& windowHandle, float x, float y) const
REQUIRES(mLock);
bool isTouchTrustedLocked(const TouchOcclusionInfo& occlusionInfo) const REQUIRES(mLock);
bool isWindowObscuredAtPointLocked(const sp<android::gui::WindowInfoHandle>& windowHandle,
- int32_t x, int32_t y) const REQUIRES(mLock);
+ float x, float y) const REQUIRES(mLock);
bool isWindowObscuredLocked(const sp<android::gui::WindowInfoHandle>& windowHandle) const
REQUIRES(mLock);
std::string dumpWindowForTouchOcclusion(const android::gui::WindowInfo* info,
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index f0f4d93ecd..621d9eadb8 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -5361,6 +5361,94 @@ TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations)
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,