Fix drag and drop (2/3)

Handle InputWindowCommands in SurfaceFlinger. Send transferTouchFocus from
SurfaceFlinger to InputFlinger.

Test: InputSurfacesTest.transfer_touch_focus
Bug: 120463595
Change-Id: I6592cc9ee4a77700ea191fd1ca337b91895b61fe
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index 610834d..ff443c6 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -36,7 +36,7 @@
     DECLARE_META_INTERFACE(InputFlinger)
 
     virtual void setInputWindows(const Vector<InputWindowInfo>& inputHandles) = 0;
-
+    virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
     virtual void registerInputChannel(const sp<InputChannel>& channel) = 0;
     virtual void unregisterInputChannel(const sp<InputChannel>& channel) = 0;
 };
@@ -50,7 +50,8 @@
     enum {
         SET_INPUT_WINDOWS_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
         REGISTER_INPUT_CHANNEL_TRANSACTION,
-        UNREGISTER_INPUT_CHANNEL_TRANSACTION
+        UNREGISTER_INPUT_CHANNEL_TRANSACTION,
+        TRANSFER_TOUCH_FOCUS
     };
 
     virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 60542bd..7fc69ff 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -133,6 +133,27 @@
         EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction());
     }
 
+    void expectMotionEvent(int motionEventType, int x, int y) {
+        InputEvent *ev = consumeEvent();
+        ASSERT_NE(ev, nullptr);
+        ASSERT_EQ(ev->getType(), AINPUT_EVENT_TYPE_MOTION);
+        MotionEvent *mev = static_cast<MotionEvent *>(ev);
+        EXPECT_EQ(motionEventType, mev->getAction());
+        EXPECT_EQ(x, mev->getX(0));
+        EXPECT_EQ(y, mev->getY(0));
+    }
+
+    void expectNoMotionEvent(int motionEventType) {
+        InputEvent *ev = consumeEvent();
+        if (ev == nullptr || ev->getType() != AINPUT_EVENT_TYPE_MOTION) {
+            // Didn't find an event or a motion event so assume action didn't occur.
+            return;
+        }
+
+        MotionEvent *mev = static_cast<MotionEvent *>(ev);
+        EXPECT_NE(motionEventType, mev->getAction());
+    }
+
     ~InputSurface() {
         mInputFlinger->unregisterInputChannel(mServerChannel);
     }
@@ -255,6 +276,15 @@
     }
 }
 
+void injectMotionEvent(std::string event, int x, int y) {
+    char *buf1, *buf2;
+    asprintf(&buf1, "%d", x);
+    asprintf(&buf2, "%d", y);
+    if (fork() == 0) {
+        execlp("input", "input", "motionevent", event.c_str(), buf1, buf2, NULL);
+    }
+}
+
 TEST_F(InputSurfacesTest, can_receive_input) {
     std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
     surface->showAt(100, 100);
@@ -439,5 +469,25 @@
     injectTap(11, 11);
     bgSurface->expectTap(1, 1);
 }
+
+TEST_F(InputSurfacesTest, transfer_touch_focus) {
+    std::unique_ptr<InputSurface> fromSurface = makeSurface(100, 100);
+
+    fromSurface->showAt(10, 10);
+    injectMotionEvent("DOWN", 11, 11);
+    fromSurface->expectMotionEvent(AMOTION_EVENT_ACTION_DOWN, 1, 1);
+
+    std::unique_ptr<InputSurface> toSurface = makeSurface(100, 100);
+    toSurface->showAt(10, 10);
+
+    sp<IBinder> fromToken = fromSurface->mServerChannel->getToken();
+    sp<IBinder> toToken = toSurface->mServerChannel->getToken();
+    SurfaceComposerClient::Transaction t;
+    t.transferTouchFocus(fromToken, toToken).apply(true);
+
+    injectMotionEvent("UP", 11, 11);
+    toSurface->expectMotionEvent(AMOTION_EVENT_ACTION_UP, 1, 1);
+    fromSurface->expectNoMotionEvent(AMOTION_EVENT_ACTION_UP);
+}
 }
 }
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
index 139570a..acf40bc 100644
--- a/libs/input/IInputFlinger.cpp
+++ b/libs/input/IInputFlinger.cpp
@@ -42,6 +42,16 @@
                 IBinder::FLAG_ONEWAY);
     }
 
+    virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
+
+        data.writeStrongBinder(fromToken);
+        data.writeStrongBinder(toToken);
+        remote()->transact(BnInputFlinger::TRANSFER_TOUCH_FOCUS, data, &reply,
+                IBinder::FLAG_ONEWAY);
+    }
+
     virtual void registerInputChannel(const sp<InputChannel>& channel) {
         Parcel data, reply;
         data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
@@ -90,6 +100,13 @@
         unregisterInputChannel(channel);
         break;
     }
+    case TRANSFER_TOUCH_FOCUS: {
+        CHECK_INTERFACE(IInputFlinger, data, reply);
+        sp<IBinder> fromToken = data.readStrongBinder();
+        sp<IBinder> toToken = data.readStrongBinder();
+        transferTouchFocus(fromToken, toToken);
+        break;
+    }
     default:
         return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 6173452..7997928 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -2386,7 +2386,8 @@
             }
 
             InputTarget target;
-            sp<InputWindowHandle> windowHandle = getWindowHandleLocked(connection->inputChannel);
+            sp<InputWindowHandle> windowHandle = getWindowHandleLocked(
+                    connection->inputChannel->getToken());
             if (windowHandle != nullptr) {
                 const InputWindowInfo* windowInfo = windowHandle->getInfo();
                 target.xOffset = -windowInfo->frameLeft;
@@ -3024,13 +3025,13 @@
 }
 
 sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
-        const sp<InputChannel>& inputChannel) const {
+        const sp<IBinder>& windowHandleToken) const {
     for (auto& it : mWindowHandlesByDisplay) {
         const Vector<sp<InputWindowHandle>> windowHandles = it.second;
         size_t numWindows = windowHandles.size();
         for (size_t i = 0; i < numWindows; i++) {
             const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
-            if (windowHandle->getToken() == inputChannel->getToken()) {
+            if (windowHandle->getToken() == windowHandleToken) {
                 return windowHandle;
             }
         }
@@ -3375,27 +3376,30 @@
 
 bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel,
         const sp<InputChannel>& toChannel) {
+    return transferTouchFocus(fromChannel->getToken(), toChannel->getToken());
+}
+
+bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
+    if (fromToken == toToken) {
 #if DEBUG_FOCUS
-    ALOGD("transferTouchFocus: fromChannel=%s, toChannel=%s",
-            fromChannel->getName().c_str(), toChannel->getName().c_str());
+        ALOGD("Trivial transfer to same window.");
 #endif
+        return true;
+    }
+
     { // acquire lock
         AutoMutex _l(mLock);
 
-        sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromChannel);
-        sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toChannel);
+        sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromToken);
+        sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toToken);
+#if DEBUG_FOCUS
+        ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s",
+            fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str());
+#endif
         if (fromWindowHandle == nullptr || toWindowHandle == nullptr) {
-#if DEBUG_FOCUS
-            ALOGD("Cannot transfer focus because from or to window not found.");
-#endif
+            ALOGW("Cannot transfer focus because from or to window not found.");
             return false;
         }
-        if (fromWindowHandle == toWindowHandle) {
-#if DEBUG_FOCUS
-            ALOGD("Trivial transfer to same window.");
-#endif
-            return true;
-        }
         if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) {
 #if DEBUG_FOCUS
             ALOGD("Cannot transfer focus because windows are on different displays.");
@@ -3433,6 +3437,9 @@
             return false;
         }
 
+
+        sp<InputChannel> fromChannel = getInputChannelLocked(fromToken);
+        sp<InputChannel> toChannel = getInputChannelLocked(toToken);
         ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel);
         ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel);
         if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) {
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 7e6de6a..970632e 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -343,11 +343,12 @@
      */
     virtual void setInputFilterEnabled(bool enabled) = 0;
 
-    /* Transfers touch focus from the window associated with one channel to the
-     * window associated with the other channel.
+    /* Transfers touch focus from one window to another window.
      *
      * Returns true on success.  False if the window did not actually have touch focus.
      */
+    virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
+
     virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
             const sp<InputChannel>& toChannel) = 0;
 
@@ -414,6 +415,7 @@
     virtual void setInputDispatchMode(bool enabled, bool frozen);
     virtual void setInputFilterEnabled(bool enabled);
 
+    virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
     virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
             const sp<InputChannel>& toChannel);
 
@@ -995,7 +997,7 @@
     std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay;
     // Get window handles by display, return an empty vector if not found.
     Vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const;
-    sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const;
+    sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const;
     sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const;
     bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
 
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 15d8070..1d7ea00 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -111,6 +111,10 @@
     }
 }
 
+void InputManager::transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
+    mDispatcher->transferTouchFocus(fromToken, toToken);
+}
+
 // Used by tests only.
 void InputManager::registerInputChannel(const sp<InputChannel>& channel) {
     IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 8f7551e..ab309b1 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -91,6 +91,7 @@
     virtual sp<InputDispatcherInterface> getDispatcher();
 
     virtual void setInputWindows(const Vector<InputWindowInfo>& handles);
+    virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
 
     virtual void registerInputChannel(const sp<InputChannel>& channel);
     virtual void unregisterInputChannel(const sp<InputChannel>& channel);
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 82ff089..9d0be95 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -40,6 +40,7 @@
 
     virtual status_t dump(int fd, const Vector<String16>& args);
     void setInputWindows(const Vector<InputWindowInfo>&) {}
+    void transferTouchFocus(const sp<IBinder>&, const sp<IBinder>&) {}
     void registerInputChannel(const sp<InputChannel>&) {}
     void unregisterInputChannel(const sp<InputChannel>&) {}
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 13997be..467b7da 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2738,6 +2738,7 @@
     if (inputChanged || mVisibleRegionsDirty) {
         updateInputWindows();
     }
+    executeInputWindowCommands();
 
     updateCursorAsync();
 }
@@ -2762,6 +2763,23 @@
     mInputFlinger->setInputWindows(inputHandles);
 }
 
+void SurfaceFlinger::executeInputWindowCommands() {
+    if (!mInputFlinger) {
+        return;
+    }
+
+    for (const auto& transferTouchFocusCommand : mInputWindowCommands.transferTouchFocusCommands) {
+        if (transferTouchFocusCommand.fromToken != nullptr &&
+            transferTouchFocusCommand.toToken != nullptr &&
+            transferTouchFocusCommand.fromToken != transferTouchFocusCommand.toToken) {
+            mInputFlinger->transferTouchFocus(transferTouchFocusCommand.fromToken,
+                                              transferTouchFocusCommand.toToken);
+        }
+    }
+
+    mInputWindowCommands.clear();
+}
+
 void SurfaceFlinger::updateCursorAsync()
 {
     for (const auto& [token, display] : mDisplays) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index bfc87a0..38c2fda 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -543,6 +543,7 @@
     void handleTransactionLocked(uint32_t transactionFlags);
 
     void updateInputWindows();
+    void executeInputWindowCommands();
     void updateCursorAsync();
 
     /* handlePageFlip - latch a new buffer if available and compute the dirty