Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 93b27491 authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

InputDispatcher: Provide a way to transfer the entire gesture

In this CL, we modify the behaviour of 'transferTouchGesture' to also
allow the caller to request that the entire gesture is transferred to
the destination window.

Suppose the original window receives ACTION_DOWN and calls
transferTouchGesture to the destination window. Before this CL, the
subsequent pointers would always be routed to the original window.

In this CL, the caller of 'transferTouchGesture' can choose to transfer
the 'entire gesture', meaning that subsequent pointers from the same
gesture that land in the original window would automatically be sent to
the destination window.

Bug: 397979572
Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST
Flag: com.android.input.flags.allow_transfer_of_entire_gesture
Change-Id: I760ddb8aa8f329d0b21788e6d6e83c802015ee1d
parent b1fd1868
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -112,6 +112,16 @@ flag {
  bug: "330752824"
}

flag {
  name: "allow_transfer_of_entire_gesture"
  namespace: "input"
  description: "When calling 'transferTouchGesture', the entire gesture (including new POINTER_DOWN events from the same device) will be automatically transferred to the destination window"
  bug: "397979572"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}

flag {
  name: "enable_keyboard_classifier"
  namespace: "input"
+39 −10
Original line number Diff line number Diff line
@@ -2447,6 +2447,24 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets(
            return injectionError(InputEventInjectionResult::TARGET_MISMATCH);
        }

        if (newTouchedWindowHandle != nullptr &&
            maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) {
            // Check if this should be redirected to another window, in case this window previously
            // called 'transferTouch' for this gesture.
            const auto it =
                    std::find_if(tempTouchState.windows.begin(), tempTouchState.windows.end(),
                                 [&](const TouchedWindow& touchedWindow) {
                                     return touchedWindow.forwardingWindowToken ==
                                             newTouchedWindowHandle->getToken() &&
                                             touchedWindow.hasTouchingPointers(entry.deviceId);
                                 });
            if (it != tempTouchState.windows.end()) {
                LOG(INFO) << "Forwarding pointer from " << newTouchedWindowHandle->getName()
                          << " to " << it->windowHandle->getName();
                newTouchedWindowHandle = it->windowHandle;
            }
        }

        std::vector<sp<WindowInfoHandle>> newTouchedWindows =
                findTouchedSpyWindowsAt(displayId, x, y, isStylus, entry.deviceId, mWindowInfos);
        if (newTouchedWindowHandle != nullptr) {
@@ -2487,7 +2505,8 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets(
                                                         isDownOrPointerDown
                                                                 ? std::make_optional(
                                                                           entry.eventTime)
                                                                 : std::nullopt);
                                                                 : std::nullopt,
                                                         /*forwardingWindowToken=*/nullptr);
                if (!addResult.ok()) {
                    LOG(ERROR) << "Error while processing " << entry << " for "
                               << windowHandle->getName();
@@ -2514,7 +2533,8 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets(
                        tempTouchState.addOrUpdateWindow(wallpaper,
                                                         InputTarget::DispatchMode::AS_IS,
                                                         wallpaperFlags, entry.deviceId, {pointer},
                                                         entry.eventTime);
                                                         entry.eventTime,
                                                         /*forwardingWindowToken=*/nullptr);
                    }
                }
            }
@@ -2613,7 +2633,8 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets(
                tempTouchState.addOrUpdateWindow(newTouchedWindowHandle,
                                                 InputTarget::DispatchMode::SLIPPERY_ENTER,
                                                 targetFlags, entry.deviceId, {pointer},
                                                 entry.eventTime);
                                                 entry.eventTime,
                                                 /*forwardingWindowToken=*/nullptr);

                // Check if the wallpaper window should deliver the corresponding event.
                slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle,
@@ -5770,7 +5791,7 @@ void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) {
}

bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
                                           bool isDragDrop) {
                                           bool isDragDrop, bool transferEntireGesture) {
    if (fromToken == toToken) {
        LOG_IF(INFO, DEBUG_FOCUS) << "Trivial transfer to same window.";
        return true;
@@ -5784,7 +5805,7 @@ bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const s
                                   "transferring touch from this window to another window",
                                   traceContext.getTracker());

        auto result = mTouchStates.transferTouchGesture(fromToken, toToken);
        auto result = mTouchStates.transferTouchGesture(fromToken, toToken, transferEntireGesture);
        if (!result.has_value()) {
            return false;
        }
@@ -5828,7 +5849,8 @@ std::optional<std::tuple<sp<gui::WindowInfoHandle>, DeviceId, std::vector<Pointe
                         std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>,
                         std::list<InputDispatcher::DispatcherTouchState::PointerDownArgs>>>
InputDispatcher::DispatcherTouchState::transferTouchGesture(const sp<android::IBinder>& fromToken,
                                                            const sp<android::IBinder>& toToken) {
                                                            const sp<android::IBinder>& toToken,
                                                            bool transferEntireGesture) {
    // Find the target touch state and touched window by fromToken.
    auto touchStateWindowAndDisplay = findTouchStateWindowAndDisplay(fromToken);
    if (!touchStateWindowAndDisplay.has_value()) {
@@ -5871,8 +5893,12 @@ InputDispatcher::DispatcherTouchState::transferTouchGesture(const sp<android::IB
    }
    // Transferring touch focus using this API should not effect the focused window.
    newTargetFlags |= InputTarget::Flags::NO_FOCUS_CHANGE;
    sp<IBinder> forwardingWindowToken;
    if (transferEntireGesture && com::android::input::flags::allow_transfer_of_entire_gesture()) {
        forwardingWindowToken = fromToken;
    }
    state.addOrUpdateWindow(toWindowHandle, InputTarget::DispatchMode::AS_IS, newTargetFlags,
                            deviceId, pointers, downTimeInTarget);
                            deviceId, pointers, downTimeInTarget, forwardingWindowToken);

    // Synthesize cancel for old window and down for new window.
    std::shared_ptr<Connection> fromConnection = mConnectionManager.getConnection(fromToken);
@@ -5954,7 +5980,8 @@ bool InputDispatcher::transferTouchOnDisplay(const sp<IBinder>& destChannelToken
        fromToken = from->getToken();
    } // release lock

    return transferTouchGesture(fromToken, destChannelToken);
    return transferTouchGesture(fromToken, destChannelToken, /*isDragDrop=*/false,
                                /*transferEntireGesture=*/false);
}

void InputDispatcher::resetAndDropEverythingLocked(const char* reason) {
@@ -7132,7 +7159,8 @@ void InputDispatcher::DispatcherTouchState::slipWallpaperTouch(
        state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::SLIPPERY_ENTER,
                                InputTarget::Flags::WINDOW_IS_OBSCURED |
                                        InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED,
                                deviceId, pointers, entry.eventTime);
                                deviceId, pointers, entry.eventTime,
                                /*forwardingWindowToken=*/nullptr);
    }
}

@@ -7173,7 +7201,8 @@ InputDispatcher::DispatcherTouchState::transferWallpaperTouch(
        wallpaperFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED |
                InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED;
        state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::AS_IS, wallpaperFlags,
                                deviceId, pointers, downTimeInTarget);
                                deviceId, pointers, downTimeInTarget,
                                /*forwardingWindowToken=*/nullptr);
        std::shared_ptr<Connection> wallpaperConnection =
                mConnectionManager.getConnection(newWallpaper->getToken());
        if (wallpaperConnection != nullptr) {
+3 −2
Original line number Diff line number Diff line
@@ -127,7 +127,7 @@ public:
    void setMaximumObscuringOpacityForTouch(float opacity) override;

    bool transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
                              bool isDragDrop = false) override;
                              bool isDragDrop, bool transferEntireGesture) override;
    bool transferTouchOnDisplay(const sp<IBinder>& destChannelToken,
                                ui::LogicalDisplayId displayId) override;

@@ -440,7 +440,8 @@ private:
        std::optional<
                std::tuple<sp<gui::WindowInfoHandle>, DeviceId, std::vector<PointerProperties>,
                           std::list<CancellationArgs>, std::list<PointerDownArgs>>>
        transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
        transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
                             bool transferEntireGesture);

        base::Result<std::list<CancellationArgs>, status_t> pilferPointers(
                const sp<IBinder>& token, const Connection& requestingConnection);
+3 −1
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ android::base::Result<void> TouchState::addOrUpdateWindow(
        const sp<WindowInfoHandle>& windowHandle, InputTarget::DispatchMode dispatchMode,
        ftl::Flags<InputTarget::Flags> targetFlags, DeviceId deviceId,
        const std::vector<PointerProperties>& touchingPointers,
        std::optional<nsecs_t> firstDownTimeInTarget) {
        std::optional<nsecs_t> firstDownTimeInTarget, sp<IBinder> forwardingWindowToken) {
    if (touchingPointers.empty()) {
        LOG(FATAL) << __func__ << "No pointers specified for " << windowHandle->getName();
        return android::base::Error();
@@ -88,6 +88,7 @@ android::base::Result<void> TouchState::addOrUpdateWindow(
        if (touchedWindow.windowHandle == windowHandle) {
            touchedWindow.dispatchMode = dispatchMode;
            touchedWindow.targetFlags |= targetFlags;
            touchedWindow.forwardingWindowToken = forwardingWindowToken;
            // For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have
            // downTime set initially. Need to update existing window when a pointer is down for the
            // window.
@@ -103,6 +104,7 @@ android::base::Result<void> TouchState::addOrUpdateWindow(
    touchedWindow.windowHandle = windowHandle;
    touchedWindow.dispatchMode = dispatchMode;
    touchedWindow.targetFlags = targetFlags;
    touchedWindow.forwardingWindowToken = forwardingWindowToken;
    touchedWindow.addTouchingPointers(deviceId, touchingPointers);
    if (firstDownTimeInTarget) {
        touchedWindow.trySetDownTimeInTarget(deviceId, *firstDownTimeInTarget);
+1 −1
Original line number Diff line number Diff line
@@ -47,7 +47,7 @@ struct TouchState {
            const sp<android::gui::WindowInfoHandle>& windowHandle,
            InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags,
            DeviceId deviceId, const std::vector<PointerProperties>& touchingPointers,
            std::optional<nsecs_t> firstDownTimeInTarget);
            std::optional<nsecs_t> firstDownTimeInTarget, sp<IBinder> forwardingWindowToken);
    void addHoveringPointerToWindow(const sp<android::gui::WindowInfoHandle>& windowHandle,
                                    DeviceId deviceId, const PointerProperties& pointer, float x,
                                    float y);
Loading