Fix the drag window still alive after drop failed

We should report the invalid drop window even if there is no visible
window can be found, the DragState from WindowManager side would
decide playing a cancel animation or remove the drag window immediately.

Test: atest CrossAppDragAndDrop
Test: atest inputflinger_tests
Bug: 182792292
Bug: 183880545
Bug: 183880412
Bug: 182234653
Bug: 183877512
Change-Id: I017caeb2ed953e395831cd5b77186f5ab3d33765
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 073455a..4e05847 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2326,6 +2326,8 @@
     if (dropWindow) {
         vec2 local = dropWindow->getInfo()->transform.transform(x, y);
         notifyDropWindowLocked(dropWindow->getToken(), local.x, local.y);
+    } else {
+        notifyDropWindowLocked(nullptr, 0, 0);
     }
     mDragState.reset();
 }
@@ -2372,6 +2374,7 @@
     } else if (maskedAction == AMOTION_EVENT_ACTION_UP) {
         finishDragAndDrop(entry.displayId, x, y);
     } else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
+        notifyDropWindowLocked(nullptr, 0, 0);
         mDragState.reset();
     }
 }
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index b62fce4..31d6900 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -268,7 +268,9 @@
 
     void assertDropTargetEquals(const sp<IBinder>& targetToken) {
         std::scoped_lock lock(mLock);
+        ASSERT_TRUE(mNotifyDropWindowWasCalled);
         ASSERT_EQ(targetToken, mDropTargetWindowToken);
+        mNotifyDropWindowWasCalled = false;
     }
 
 private:
@@ -290,6 +292,7 @@
     std::condition_variable mNotifyAnr;
 
     sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock);
+    bool mNotifyDropWindowWasCalled GUARDED_BY(mLock) = false;
 
     void notifyConfigurationChanged(nsecs_t when) override {
         std::scoped_lock lock(mLock);
@@ -403,6 +406,7 @@
 
     void notifyDropWindow(const sp<IBinder>& token, float x, float y) override {
         std::scoped_lock lock(mLock);
+        mNotifyDropWindowWasCalled = true;
         mDropTargetWindowToken = token;
     }
 
@@ -4951,4 +4955,40 @@
     mSecondWindow->assertNoEvents();
 }
 
+TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) {
+    performDrag();
+
+    // Set second window invisible.
+    mSecondWindow->setVisible(false);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}});
+
+    // Move on window.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+                                ADISPLAY_ID_DEFAULT, {50, 50}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+    mWindow->consumeDragEvent(false, 50, 50);
+    mSecondWindow->assertNoEvents();
+
+    // Move to another window.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+                                ADISPLAY_ID_DEFAULT, {150, 50}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+    mWindow->consumeDragEvent(true, 150, 50);
+    mSecondWindow->assertNoEvents();
+
+    // drop to another window.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                             {150, 50}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+    mFakePolicy->assertDropTargetEquals(nullptr);
+    mWindow->assertNoEvents();
+    mSecondWindow->assertNoEvents();
+}
+
 } // namespace android::inputdispatcher