Add test to call setInputWindows twice

Currently, I'm observing some strange behaviour, where calling
setInputWindows twice results in the touchable region becoming empty.
Add this test to R to see what's going on, and potentially bisect on
this.

Bug: 143459140
Test: atest inputflinger_tests
Change-Id: Ia0acef5d4ee4acc29d20174fe44c9f94172ccd96
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 82ce757..e01309b 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -224,6 +224,11 @@
     validate(*this, "this->operator=");
     validate(rhs, "rhs.operator=");
 #endif
+    if (this == &rhs) {
+        // Already equal to itself
+        return *this;
+    }
+
     mStorage.clear();
     mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
     return *this;
diff --git a/libs/ui/tests/Region_test.cpp b/libs/ui/tests/Region_test.cpp
index b104a46..c6b826d 100644
--- a/libs/ui/tests/Region_test.cpp
+++ b/libs/ui/tests/Region_test.cpp
@@ -152,5 +152,20 @@
     }
 }
 
+TEST_F(RegionTest, EqualsToSelf) {
+    Region touchableRegion;
+    touchableRegion.orSelf(Rect(0, 0, 100, 100));
+
+    ASSERT_TRUE(touchableRegion.contains(50, 50));
+
+    // Compiler prevents us from directly calling 'touchableRegion = touchableRegion'
+    Region& referenceTouchableRegion = touchableRegion;
+    touchableRegion = referenceTouchableRegion;
+
+    ASSERT_FALSE(touchableRegion.isEmpty());
+
+    ASSERT_TRUE(touchableRegion.contains(50, 50));
+}
+
 }; // namespace android
 
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 365d43d..e94737f 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -811,13 +811,15 @@
 }
 
 static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t source,
-                                int32_t displayId, int32_t x = 100, int32_t y = 200) {
-    return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, x, y);
+                                int32_t displayId, const PointF& location = {100, 200}) {
+    return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, location.x,
+                             location.y);
 }
 
 static int32_t injectMotionUp(const sp<InputDispatcher>& dispatcher, int32_t source,
-                              int32_t displayId, int32_t x = 100, int32_t y = 200) {
-    return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, x, y);
+                              int32_t displayId, const PointF& location = {100, 200}) {
+    return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, location.x,
+                             location.y);
 }
 
 static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) {
@@ -881,6 +883,55 @@
     window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
 }
 
+/**
+ * Calling setInputWindows once with FLAG_NOT_TOUCH_MODAL should not cause any issues.
+ * To ensure that window receives only events that were directly inside of it, add
+ * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input
+ * when finding touched windows.
+ * This test serves as a sanity check for the next test, where setInputWindows is
+ * called twice.
+ */
+TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> window =
+            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    window->setFrame(Rect(0, 0, 100, 100));
+    window->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {50, 50}))
+            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+    // Window should receive motion event.
+    window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+}
+
+/**
+ * Calling setInputWindows twice, with the same info, should not cause any issues.
+ * To ensure that window receives only events that were directly inside of it, add
+ * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input
+ * when finding touched windows.
+ */
+TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> window =
+            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    window->setFrame(Rect(0, 0, 100, 100));
+    window->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {50, 50}))
+            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+    // Window should receive motion event.
+    window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+}
+
 // The foreground window should receive the first touch down event.
 TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
     sp<FakeApplicationHandle> application = new FakeApplicationHandle();
@@ -1822,7 +1873,6 @@
                 new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
         mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
         mFocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
-        mFocusedWindowTouchPoint = 60;
 
         // Set focused application.
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -1843,15 +1893,16 @@
 protected:
     sp<FakeWindowHandle> mUnfocusedWindow;
     sp<FakeWindowHandle> mFocusedWindow;
-    int32_t mFocusedWindowTouchPoint;
+    static constexpr PointF FOCUSED_WINDOW_TOUCH_POINT = {60, 60};
 };
 
 // Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
 // DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received
 // the onPointerDownOutsideFocus callback.
 TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) {
-    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
-            AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20, 20))
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {20, 20}))
             << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
     mUnfocusedWindow->consumeMotionDown();
 
@@ -1863,8 +1914,8 @@
 // DOWN on the window that doesn't have focus. Ensure no window received the
 // onPointerDownOutsideFocus callback.
 TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) {
-    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
-            AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, 20, 20))
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, {20, 20}))
             << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
     mFocusedWindow->consumeMotionDown();
 
@@ -1890,7 +1941,7 @@
         OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
     ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
               injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
-                               mFocusedWindowTouchPoint, mFocusedWindowTouchPoint))
+                               FOCUSED_WINDOW_TOUCH_POINT))
             << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
     mFocusedWindow->consumeMotionDown();