Merge "Move drag event to InputDispatcher (5/n)" into sc-dev
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index b2ddb42..7bd0c6b 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -113,6 +113,8 @@
 
     void setPointerCapture(bool enabled) override {}
 
+    void notifyDropWindow(const sp<IBinder>&, float x, float y) override {}
+
     InputDispatcherConfiguration mConfig;
 };
 
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index e5fb26c..f3ef64b 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -287,6 +287,8 @@
     int32_t pid;
     nsecs_t consumeTime; // time when the event was consumed by InputConsumer
     int32_t displayId;
+    float x;
+    float y;
 };
 
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index fe46d17..397a9d7 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2345,6 +2345,10 @@
         }
     } else if (maskedAction == AMOTION_EVENT_ACTION_UP ||
                maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
+        if (state.dragHoverWindowHandle && maskedAction == AMOTION_EVENT_ACTION_UP) {
+            vec2 local = state.dragHoverWindowHandle->getInfo()->transform.transform(x, y);
+            notifyDropWindowLocked(state.dragHoverWindowHandle->getToken(), local.x, local.y);
+        }
         state.dragWindow = nullptr;
         state.dragHoverWindowHandle = nullptr;
     }
@@ -5302,6 +5306,15 @@
     postCommandLocked(std::move(commandEntry));
 }
 
+void InputDispatcher::notifyDropWindowLocked(const sp<IBinder>& token, float x, float y) {
+    std::unique_ptr<CommandEntry> commandEntry =
+            std::make_unique<CommandEntry>(&InputDispatcher::doNotifyDropWindowLockedInterruptible);
+    commandEntry->newToken = token;
+    commandEntry->x = x;
+    commandEntry->y = y;
+    postCommandLocked(std::move(commandEntry));
+}
+
 void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
     if (connection == nullptr) {
         LOG_ALWAYS_FATAL("Caller must check for nullness");
@@ -5411,6 +5424,13 @@
     mLock.lock();
 }
 
+void InputDispatcher::doNotifyDropWindowLockedInterruptible(CommandEntry* commandEntry) {
+    sp<IBinder> newToken = commandEntry->newToken;
+    mLock.unlock();
+    mPolicy->notifyDropWindow(newToken, commandEntry->x, commandEntry->y);
+    mLock.lock();
+}
+
 void InputDispatcher::doNotifyNoFocusedWindowAnrLockedInterruptible(CommandEntry* commandEntry) {
     mLock.unlock();
 
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index b2f3625..593ec23 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -592,6 +592,7 @@
     void onFocusChangedLocked(const FocusResolver::FocusChanges& changes) REQUIRES(mLock);
     void notifyFocusChangedLocked(const sp<IBinder>& oldFocus, const sp<IBinder>& newFocus)
             REQUIRES(mLock);
+    void notifyDropWindowLocked(const sp<IBinder>& token, float x, float y) REQUIRES(mLock);
     void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
     void onAnrLocked(std::shared_ptr<InputApplicationHandle> application) REQUIRES(mLock);
     void onUntrustedTouchLocked(const std::string& obscuringPackage) REQUIRES(mLock);
@@ -607,6 +608,8 @@
             REQUIRES(mLock);
     void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
     void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+    void doNotifyDropWindowLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+
     // ANR-related callbacks - start
     void doNotifyNoFocusedWindowAnrLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
     void doNotifyWindowUnresponsiveLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index 439d85e..219f45a 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -157,6 +157,9 @@
      * InputDispatcher is solely responsible for updating the Pointer Capture state.
      */
     virtual void setPointerCapture(bool enabled) = 0;
+
+    /* Notifies the policy that the drag window has moved over to another window */
+    virtual void notifyDropWindow(const sp<IBinder>& token, float x, float y) = 0;
 };
 
 } // namespace android
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 32f9b69..cedda6e 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -266,6 +266,11 @@
         mPointerCaptureEnabled.reset();
     }
 
+    void assertDropTargetEquals(const sp<IBinder>& targetToken) {
+        std::scoped_lock lock(mLock);
+        ASSERT_EQ(targetToken, mDropTargetWindowToken);
+    }
+
 private:
     std::mutex mLock;
     std::unique_ptr<InputEvent> mFilteredEvent GUARDED_BY(mLock);
@@ -284,6 +289,8 @@
     std::queue<int32_t> mResponsiveMonitorPids GUARDED_BY(mLock);
     std::condition_variable mNotifyAnr;
 
+    sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock);
+
     void notifyConfigurationChanged(nsecs_t when) override {
         std::scoped_lock lock(mLock);
         mConfigurationChangedTime = when;
@@ -392,6 +399,11 @@
         mPointerCaptureChangedCondition.notify_all();
     }
 
+    void notifyDropWindow(const sp<IBinder>& token, float x, float y) override {
+        std::scoped_lock lock(mLock);
+        mDropTargetWindowToken = token;
+    }
+
     void assertFilterInputEventWasCalled(int type, nsecs_t eventTime, int32_t action,
                                          int32_t displayId) {
         std::scoped_lock lock(mLock);
@@ -4789,4 +4801,36 @@
     mSecondWindow->assertNoEvents();
 }
 
+TEST_F(InputDispatcherDragTests, DragAndDrop) {
+    performDrag();
+
+    // 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->consumeDragEvent(false, 50, 50);
+
+    // 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(mSecondWindow->getToken());
+    mWindow->assertNoEvents();
+    mSecondWindow->assertNoEvents();
+}
+
 } // namespace android::inputdispatcher