Merge "Move occlusion detection into logical space" into main
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index 86bf0ee..ad0d99d 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -73,14 +73,6 @@
     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 32d60be..2d1b51a 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -254,10 +254,6 @@
 
     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 dc220fe..e6b37c1 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -598,6 +598,18 @@
     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);
@@ -3105,7 +3117,7 @@
  * 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);
@@ -3119,7 +3131,8 @@
             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(
@@ -3189,7 +3202,7 @@
 }
 
 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) {
@@ -3198,7 +3211,7 @@
         }
         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 13571b3..edca63e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -566,11 +566,11 @@
     };
 
     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 9375e92..6a6fc14 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -5367,6 +5367,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,