diff options
-rw-r--r-- | libs/gui/WindowInfo.cpp | 8 | ||||
-rw-r--r-- | libs/gui/include/gui/WindowInfo.h | 4 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 21 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.h | 4 | ||||
-rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 88 |
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, |