Add InputDispatcher unit tests for untrusted touches [5/n]

This is the unit test compliment of ag/12198106.

Test that taps *inside* windows with flags FLAG_WATCH_OUTSIDE_TOUCH |
FLAG_NOT_TOUCHABLE result in ACTION_OUTSIDE events. This is important
for security to make sure apps can't learn the position of touches
(outside vs inside) while letting them pass-through.

Bug: 158002302
Bug: 177840583
Fix: 110901409
Test: atest InputDispatcherUntrustedTouchesTest
Change-Id: Iaa59fa4c057c2f1d81d0e7010fddf0248adf23e5
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 209639c..8456387 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -908,6 +908,8 @@
         mInfo.addTouchableRegion(frame);
     }
 
+    void addFlags(Flags<InputWindowInfo::Flag> flags) { mInfo.flags |= flags; }
+
     void setFlags(Flags<InputWindowInfo::Flag> flags) { mInfo.flags = flags; }
 
     void setInputFeatures(InputWindowInfo::Feature features) { mInfo.inputFeatures = features; }
@@ -4318,6 +4320,17 @@
     mTouchWindow->assertNoEvents();
 }
 
+TEST_F(InputDispatcherUntrustedTouchesTest,
+       WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    w->assertNoEvents();
+}
+
 TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) {
     const sp<FakeWindowHandle>& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
@@ -4358,6 +4371,48 @@
     mTouchWindow->consumeAnyMotionDown();
 }
 
+TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_DoesNotReceiveTouch) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    w->assertNoEvents();
+}
+
+/**
+ * This is important to make sure apps can't indirectly learn the position of touches (outside vs
+ * inside) while letting them pass-through. Note that even though touch passes through the occluding
+ * window, the occluding window will still receive ACTION_OUTSIDE event.
+ */
+TEST_F(InputDispatcherUntrustedTouchesTest,
+       WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
+    w->addFlags(InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    w->consumeMotionOutside();
+}
+
+TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) {
+    const sp<FakeWindowHandle>& w =
+            getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f);
+    w->addFlags(InputWindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}});
+
+    touch();
+
+    InputEvent* event = w->consume();
+    ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
+    MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
+    EXPECT_EQ(0.0f, motionEvent.getRawPointerCoords(0)->getX());
+    EXPECT_EQ(0.0f, motionEvent.getRawPointerCoords(0)->getY());
+}
+
 TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
     const sp<FakeWindowHandle>& w =
             getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.7f);