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

Commit c539dbb9 authored by Arthur Hung's avatar Arthur Hung
Browse files

Fix wallpaper window multi-touch

If the touched window has a wallpaper, then the touch event will be
duplicated to the wallpaper window when the foreground window received
a touch event.

When the foreground supports split touch, the wallpaper should deliver
the same events of foreground window.

And when the foreground window is transferred (caused by slippery or
transfer touch) to the new touched window, it has to check if the
wallpaper window should deliver the cancel event or keep in current
touch state.

Bug: 240308355
Test: atest inputflinger_tests
Change-Id: Ie53279f18838c459e528b24709aebf739290dc41
parent c69e6ede
Loading
Loading
Loading
Loading
+153 −43
Original line number Diff line number Diff line
@@ -2060,6 +2060,12 @@ bool InputDispatcher::shouldSplitTouch(const TouchState& touchState,
        if (touchedWindow.windowHandle->getInfo()->supportsSplitTouch()) {
            continue;
        }
        if (touchedWindow.windowHandle->getInfo()->inputConfig.test(
                    gui::WindowInfo::InputConfig::IS_WALLPAPER)) {
            // Wallpaper window should not affect whether or not touch is split
            continue;
        }

        // Eventually, touchedWindow will contain the deviceId of each pointer that's currently
        // being sent there. For now, use deviceId from touch state.
        if (entry.deviceId == touchState.deviceId && !touchedWindow.pointerIds.isEmpty()) {
@@ -2223,6 +2229,32 @@ std::vector<TouchedWindow> InputDispatcher::findTouchedWindowTargetsLocked(

            tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds,
                                             entry.eventTime);

            // If this is the pointer going down and the touched window has a wallpaper
            // then also add the touched wallpaper windows so they are locked in for the duration
            // of the touch gesture.
            // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper
            // engine only supports touch events.  We would need to add a mechanism similar
            // to View.onGenericMotionEvent to enable wallpapers to handle these events.
            if (maskedAction == AMOTION_EVENT_ACTION_DOWN ||
                maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) {
                if (targetFlags.test(InputTarget::Flags::FOREGROUND) &&
                    windowHandle->getInfo()->inputConfig.test(
                            gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
                    sp<WindowInfoHandle> wallpaper = findWallpaperWindowBelow(windowHandle);
                    if (wallpaper != nullptr) {
                        ftl::Flags<InputTarget::Flags> wallpaperFlags =
                                InputTarget::Flags::WINDOW_IS_OBSCURED |
                                InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED |
                                InputTarget::Flags::DISPATCH_AS_IS;
                        if (isSplit) {
                            wallpaperFlags |= InputTarget::Flags::SPLIT;
                        }
                        tempTouchState.addOrUpdateWindow(wallpaper, wallpaperFlags, pointerIds,
                                                         entry.eventTime);
                    }
                }
            }
        }

        // If any existing window is pilfering pointers from newly added window, remove it
@@ -2307,6 +2339,10 @@ std::vector<TouchedWindow> InputDispatcher::findTouchedWindowTargetsLocked(
                pointerIds.markBit(entry.pointerProperties[0].id);
                tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds,
                                                 entry.eventTime);

                // Check if the wallpaper window should deliver the corresponding event.
                slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle,
                                   tempTouchState, pointerIds);
            }
        }

@@ -2413,38 +2449,6 @@ std::vector<TouchedWindow> InputDispatcher::findTouchedWindowTargetsLocked(
        }
    }

    // If this is the first pointer going down and the touched window has a wallpaper
    // then also add the touched wallpaper windows so they are locked in for the duration
    // of the touch gesture.
    // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper
    // engine only supports touch events.  We would need to add a mechanism similar
    // to View.onGenericMotionEvent to enable wallpapers to handle these events.
    if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
        sp<WindowInfoHandle> foregroundWindowHandle =
                tempTouchState.getFirstForegroundWindowHandle();
        if (foregroundWindowHandle &&
            foregroundWindowHandle->getInfo()->inputConfig.test(
                    WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
            const std::vector<sp<WindowInfoHandle>>& windowHandles =
                    getWindowHandlesLocked(displayId);
            for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
                const WindowInfo* info = windowHandle->getInfo();
                if (info->displayId == displayId &&
                    windowHandle->getInfo()->inputConfig.test(
                            WindowInfo::InputConfig::IS_WALLPAPER)) {
                    BitSet32 pointerIds;
                    pointerIds.markBit(entry.pointerProperties[0].id);
                    tempTouchState.addOrUpdateWindow(windowHandle,
                                                     InputTarget::Flags::WINDOW_IS_OBSCURED |
                                                             InputTarget::Flags::
                                                                     WINDOW_IS_PARTIALLY_OBSCURED |
                                                             InputTarget::Flags::DISPATCH_AS_IS,
                                                     pointerIds, entry.eventTime);
                }
            }
        }
    }

    // Success!  Output targets.
    touchedWindows = tempTouchState.windows;
    outInjectionResult = InputEventInjectionResult::SUCCEEDED;
@@ -3726,7 +3730,8 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
}

void InputDispatcher::synthesizePointerDownEventsForConnectionLocked(
        const nsecs_t downTime, const sp<Connection>& connection) {
        const nsecs_t downTime, const sp<Connection>& connection,
        ftl::Flags<InputTarget::Flags> targetFlags) {
    if (connection->status == Connection::Status::BROKEN) {
        return;
    }
@@ -3752,7 +3757,7 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked(
        target.globalScaleFactor = windowInfo->globalScaleFactor;
    }
    target.inputChannel = connection->inputChannel;
    target.flags = InputTarget::Flags::DISPATCH_AS_IS;
    target.flags = targetFlags;

    const bool wasEmpty = connection->outboundQueue.empty();
    for (std::unique_ptr<EventEntry>& downEventEntry : downEvents) {
@@ -3787,6 +3792,16 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked(
    }
}

void InputDispatcher::synthesizeCancelationEventsForWindowLocked(
        const sp<WindowInfoHandle>& windowHandle, const CancelationOptions& options) {
    if (windowHandle != nullptr) {
        sp<Connection> wallpaperConnection = getConnectionLocked(windowHandle->getToken());
        if (wallpaperConnection != nullptr) {
            synthesizeCancelationEventsForConnectionLocked(wallpaperConnection, options);
        }
    }
}

std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent(
        const MotionEntry& originalMotionEntry, BitSet32 pointerIds, nsecs_t splitDownTime) {
    ALOG_ASSERT(pointerIds.value != 0);
@@ -4847,14 +4862,7 @@ void InputDispatcher::setInputWindowsLocked(
                        touchedWindow.windowHandle->getInfo()->inputConfig.test(
                                gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
                        sp<WindowInfoHandle> wallpaper = state.getWallpaperWindow();
                        if (wallpaper != nullptr) {
                            sp<Connection> wallpaperConnection =
                                    getConnectionLocked(wallpaper->getToken());
                            if (wallpaperConnection != nullptr) {
                                synthesizeCancelationEventsForConnectionLocked(wallpaperConnection,
                                                                               options);
                            }
                        }
                        synthesizeCancelationEventsForWindowLocked(wallpaper, options);
                    }
                }
                state.windows.erase(state.windows.begin() + i);
@@ -5155,6 +5163,7 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<
        // Erase old window.
        ftl::Flags<InputTarget::Flags> oldTargetFlags = touchedWindow->targetFlags;
        BitSet32 pointerIds = touchedWindow->pointerIds;
        sp<WindowInfoHandle> fromWindowHandle = touchedWindow->windowHandle;
        state->removeWindowByToken(fromToken);

        // Add new window.
@@ -5187,7 +5196,12 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<
                    options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
                            "transferring touch focus from this window to another window");
            synthesizeCancelationEventsForConnectionLocked(fromConnection, options);
            synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection);
            synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection,
                                                           newTargetFlags);

            // Check if the wallpaper window should deliver the corresponding event.
            transferWallpaperTouch(oldTargetFlags, newTargetFlags, fromWindowHandle, toWindowHandle,
                                   *state, pointerIds);
        }
    } // release lock

@@ -6465,4 +6479,100 @@ void InputDispatcher::setMonitorDispatchingTimeoutForTest(std::chrono::nanosecon
    mMonitorDispatchingTimeout = timeout;
}

void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags,
                                         const sp<WindowInfoHandle>& oldWindowHandle,
                                         const sp<WindowInfoHandle>& newWindowHandle,
                                         TouchState& state, const BitSet32& pointerIds) {
    const bool oldHasWallpaper = oldWindowHandle->getInfo()->inputConfig.test(
            gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER);
    const bool newHasWallpaper = targetFlags.test(InputTarget::Flags::FOREGROUND) &&
            newWindowHandle->getInfo()->inputConfig.test(
                    gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER);
    const sp<WindowInfoHandle> oldWallpaper =
            oldHasWallpaper ? state.getWallpaperWindow() : nullptr;
    const sp<WindowInfoHandle> newWallpaper =
            newHasWallpaper ? findWallpaperWindowBelow(newWindowHandle) : nullptr;
    if (oldWallpaper == newWallpaper) {
        return;
    }

    if (oldWallpaper != nullptr) {
        state.addOrUpdateWindow(oldWallpaper, InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT,
                                BitSet32(0));
    }

    if (newWallpaper != nullptr) {
        state.addOrUpdateWindow(newWallpaper,
                                InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER |
                                        InputTarget::Flags::WINDOW_IS_OBSCURED |
                                        InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED,
                                pointerIds);
    }
}

void InputDispatcher::transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags,
                                             ftl::Flags<InputTarget::Flags> newTargetFlags,
                                             const sp<WindowInfoHandle> fromWindowHandle,
                                             const sp<WindowInfoHandle> toWindowHandle,
                                             TouchState& state, const BitSet32& pointerIds) {
    const bool oldHasWallpaper = oldTargetFlags.test(InputTarget::Flags::FOREGROUND) &&
            fromWindowHandle->getInfo()->inputConfig.test(
                    gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER);
    const bool newHasWallpaper = newTargetFlags.test(InputTarget::Flags::FOREGROUND) &&
            toWindowHandle->getInfo()->inputConfig.test(
                    gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER);

    const sp<WindowInfoHandle> oldWallpaper =
            oldHasWallpaper ? state.getWallpaperWindow() : nullptr;
    const sp<WindowInfoHandle> newWallpaper =
            newHasWallpaper ? findWallpaperWindowBelow(toWindowHandle) : nullptr;
    if (oldWallpaper == newWallpaper) {
        return;
    }

    if (oldWallpaper != nullptr) {
        CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
                                   "transferring touch focus to another window");
        state.removeWindowByToken(oldWallpaper->getToken());
        synthesizeCancelationEventsForWindowLocked(oldWallpaper, options);
    }

    if (newWallpaper != nullptr) {
        nsecs_t downTimeInTarget = now();
        ftl::Flags<InputTarget::Flags> wallpaperFlags =
                oldTargetFlags & (InputTarget::Flags::SPLIT | InputTarget::Flags::DISPATCH_AS_IS);
        wallpaperFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED |
                InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED;
        state.addOrUpdateWindow(newWallpaper, wallpaperFlags, pointerIds, downTimeInTarget);
        sp<Connection> wallpaperConnection = getConnectionLocked(newWallpaper->getToken());
        if (wallpaperConnection != nullptr) {
            sp<Connection> toConnection = getConnectionLocked(toWindowHandle->getToken());
            toConnection->inputState.mergePointerStateTo(wallpaperConnection->inputState);
            synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, wallpaperConnection,
                                                           wallpaperFlags);
        }
    }
}

sp<WindowInfoHandle> InputDispatcher::findWallpaperWindowBelow(
        const sp<WindowInfoHandle>& windowHandle) const {
    const std::vector<sp<WindowInfoHandle>>& windowHandles =
            getWindowHandlesLocked(windowHandle->getInfo()->displayId);
    bool foundWindow = false;
    for (const sp<WindowInfoHandle>& otherHandle : windowHandles) {
        if (!foundWindow && otherHandle != windowHandle) {
            continue;
        }
        if (windowHandle == otherHandle) {
            foundWindow = true;
            continue;
        }

        if (otherHandle->getInfo()->inputConfig.test(WindowInfo::InputConfig::IS_WALLPAPER)) {
            return otherHandle;
        }
    }
    return nullptr;
}

} // namespace android::inputdispatcher
+19 −1
Original line number Diff line number Diff line
@@ -628,9 +628,14 @@ private:
            REQUIRES(mLock);

    void synthesizePointerDownEventsForConnectionLocked(const nsecs_t downTime,
                                                        const sp<Connection>& connection)
                                                        const sp<Connection>& connection,
                                                        ftl::Flags<InputTarget::Flags> targetFlags)
            REQUIRES(mLock);

    void synthesizeCancelationEventsForWindowLocked(
            const sp<android::gui::WindowInfoHandle>& windowHandle,
            const CancelationOptions& options) REQUIRES(mLock);

    // Splitting motion events across windows. When splitting motion event for a target,
    // splitDownTime refers to the time of first 'down' event on that particular target
    std::unique_ptr<MotionEntry> splitMotionEvent(const MotionEntry& originalMotionEntry,
@@ -691,6 +696,19 @@ private:
    bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);

    sp<InputReporterInterface> mReporter;

    void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags,
                            const sp<android::gui::WindowInfoHandle>& oldWindowHandle,
                            const sp<android::gui::WindowInfoHandle>& newWindowHandle,
                            TouchState& state, const BitSet32& pointerIds) REQUIRES(mLock);
    void transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags,
                                ftl::Flags<InputTarget::Flags> newTargetFlags,
                                const sp<android::gui::WindowInfoHandle> fromWindowHandle,
                                const sp<android::gui::WindowInfoHandle> toWindowHandle,
                                TouchState& state, const BitSet32& pointerIds) REQUIRES(mLock);

    sp<android::gui::WindowInfoHandle> findWallpaperWindowBelow(
            const sp<android::gui::WindowInfoHandle>& windowHandle) const REQUIRES(mLock);
};

} // namespace android::inputdispatcher
+138 −60

File changed.

Preview size limit exceeded, changes collapsed.