diff options
-rw-r--r-- | include/input/PrintTools.h | 3 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 106 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.h | 6 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/TouchState.cpp | 74 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/TouchState.h | 15 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/TouchedWindow.cpp | 218 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/TouchedWindow.h | 55 |
7 files changed, 352 insertions, 125 deletions
diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h index 0ca6fa30ce..0e3fbb1982 100644 --- a/include/input/PrintTools.h +++ b/include/input/PrintTools.h @@ -27,6 +27,9 @@ namespace android { template <size_t N> std::string bitsetToString(const std::bitset<N>& bitset) { + if (bitset.none()) { + return "<none>"; + } return bitset.to_string(); } diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 6f2464b41b..d91fe4c9f1 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -654,7 +654,6 @@ std::vector<TouchedWindow> getHoveringWindowsLocked(const TouchState* oldState, TouchedWindow touchedWindow; touchedWindow.windowHandle = oldWindow; touchedWindow.targetFlags = InputTarget::Flags::DISPATCH_AS_HOVER_EXIT; - touchedWindow.pointerIds.set(pointerId); out.push_back(touchedWindow); } } @@ -673,7 +672,7 @@ std::vector<TouchedWindow> getHoveringWindowsLocked(const TouchState* oldState, } touchedWindow.targetFlags = InputTarget::Flags::DISPATCH_AS_IS; } - touchedWindow.pointerIds.set(pointerId); + touchedWindow.addHoveringPointer(entry.deviceId, pointerId); if (canReceiveForegroundTouches(*newWindow->getInfo())) { touchedWindow.targetFlags |= InputTarget::Flags::FOREGROUND; } @@ -2195,8 +2194,8 @@ std::vector<Monitor> InputDispatcher::selectResponsiveMonitorsLocked( /** * In general, touch should be always split between windows. Some exceptions: * 1. Don't split touch is if we have an active pointer down, and a new pointer is going down that's - * from the same device, *and* the window that's receiving the current pointer does not support - * split touch. + * from the same device, *and* the window that's receiving the current pointer does not support + * split touch. * 2. Don't split mouse events */ bool InputDispatcher::shouldSplitTouch(const TouchState& touchState, @@ -2221,7 +2220,8 @@ bool InputDispatcher::shouldSplitTouch(const TouchState& touchState, // 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.any()) { + if (entry.deviceId == touchState.deviceId && + touchedWindow.hasTouchingPointers(entry.deviceId)) { return false; } } @@ -2404,7 +2404,7 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( // still add a window to the touch state. We should avoid doing that, but some of the // later checks ("at least one foreground window") rely on this in order to dispatch // the event properly, so that needs to be updated, possibly by looking at InputTargets. - tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds, + tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, entry.deviceId, pointerIds, isDownOrPointerDown ? std::make_optional(entry.eventTime) : std::nullopt); @@ -2428,8 +2428,8 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( if (isSplit) { wallpaperFlags |= InputTarget::Flags::SPLIT; } - tempTouchState.addOrUpdateWindow(wallpaper, wallpaperFlags, pointerIds, - entry.eventTime); + tempTouchState.addOrUpdateWindow(wallpaper, wallpaperFlags, entry.deviceId, + pointerIds, entry.eventTime); } } } @@ -2440,12 +2440,12 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( // which is a specific behaviour that we want. const int32_t pointerId = entry.pointerProperties[pointerIndex].id; for (TouchedWindow& touchedWindow : tempTouchState.windows) { - if (touchedWindow.pointerIds.test(pointerId) && - touchedWindow.pilferedPointerIds.count() > 0) { + if (touchedWindow.hasTouchingPointer(entry.deviceId, pointerId) && + touchedWindow.hasPilferingPointers(entry.deviceId)) { // This window is already pilfering some pointers, and this new pointer is also // going to it. Therefore, take over this pointer and don't give it to anyone // else. - touchedWindow.pilferedPointerIds.set(pointerId); + touchedWindow.addPilferingPointer(entry.deviceId, pointerId); } } @@ -2517,7 +2517,7 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( tempTouchState.getTouchedWindow(oldTouchedWindowHandle); addWindowTargetLocked(oldTouchedWindowHandle, InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT, pointerIds, - touchedWindow.firstDownTimeInTarget, targets); + touchedWindow.getDownTimeInTarget(entry.deviceId), targets); // Make a slippery entrance into the new window. if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { @@ -2538,13 +2538,14 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( targetFlags |= InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED; } - tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds, - entry.eventTime); + tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, + entry.deviceId, pointerIds, entry.eventTime); // Check if the wallpaper window should deliver the corresponding event. slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle, - tempTouchState, pointerId, targets); - tempTouchState.removeTouchedPointerFromWindow(pointerId, oldTouchedWindowHandle); + tempTouchState, entry.deviceId, pointerId, targets); + tempTouchState.removeTouchingPointerFromWindow(entry.deviceId, pointerId, + oldTouchedWindowHandle); } } @@ -2558,7 +2559,8 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) { continue; } - touchedWindow.pointerIds.set(entry.pointerProperties[pointerIndex].id); + touchedWindow.addTouchingPointer(entry.deviceId, + entry.pointerProperties[pointerIndex].id); } } } @@ -2570,7 +2572,7 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( for (const TouchedWindow& touchedWindow : hoveringWindows) { std::optional<InputTarget> target = createInputTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, - touchedWindow.firstDownTimeInTarget); + touchedWindow.getDownTimeInTarget(entry.deviceId)); if (!target) { continue; } @@ -2627,15 +2629,16 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( // Output targets from the touch state. for (const TouchedWindow& touchedWindow : tempTouchState.windows) { - if (touchedWindow.pointerIds.none() && !touchedWindow.hasHoveringPointers(entry.deviceId)) { + if (!touchedWindow.hasTouchingPointers(entry.deviceId) && + !touchedWindow.hasHoveringPointers(entry.deviceId)) { // Windows with hovering pointers are getting persisted inside TouchState. // Do not send this event to those windows. continue; } addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, - touchedWindow.pointerIds, touchedWindow.firstDownTimeInTarget, - targets); + touchedWindow.getTouchingPointers(entry.deviceId), + touchedWindow.getDownTimeInTarget(entry.deviceId), targets); } // During targeted injection, only allow owned targets to receive events @@ -2694,7 +2697,7 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( } } else if (maskedAction == AMOTION_EVENT_ACTION_UP) { // Pointer went up. - tempTouchState.removeTouchedPointer(entry.pointerProperties[0].id); + tempTouchState.removeTouchingPointer(entry.deviceId, entry.pointerProperties[0].id); } else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) { // All pointers up or canceled. tempTouchState.reset(); @@ -2711,8 +2714,8 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( for (size_t i = 0; i < tempTouchState.windows.size();) { TouchedWindow& touchedWindow = tempTouchState.windows[i]; - touchedWindow.pointerIds.reset(pointerId); - if (touchedWindow.pointerIds.none()) { + touchedWindow.removeTouchingPointer(entry.deviceId, pointerId); + if (!touchedWindow.hasTouchingPointers(entry.deviceId)) { tempTouchState.windows.erase(tempTouchState.windows.begin() + i); continue; } @@ -5451,14 +5454,22 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< // Find the target touch state and touched window by fromToken. auto [state, touchedWindow, displayId] = findTouchStateWindowAndDisplayLocked(fromToken); + if (state == nullptr || touchedWindow == nullptr) { - ALOGD("Focus transfer failed because from window is not being touched."); + ALOGD("Touch transfer failed because from window is not being touched."); + return false; + } + std::set<int32_t> deviceIds = touchedWindow->getTouchingDeviceIds(); + if (deviceIds.size() != 1) { + LOG(DEBUG) << "Can't transfer touch. Currently touching devices: " << dumpSet(deviceIds) + << " for window: " << touchedWindow->dump(); return false; } + const int32_t deviceId = *deviceIds.begin(); sp<WindowInfoHandle> toWindowHandle = getWindowHandleLocked(toToken, displayId); if (toWindowHandle == nullptr) { - ALOGW("Cannot transfer focus because to window not found."); + ALOGW("Cannot transfer touch because to window not found."); return false; } @@ -5470,7 +5481,7 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< // Erase old window. ftl::Flags<InputTarget::Flags> oldTargetFlags = touchedWindow->targetFlags; - std::bitset<MAX_POINTER_ID + 1> pointerIds = touchedWindow->pointerIds; + std::bitset<MAX_POINTER_ID + 1> pointerIds = touchedWindow->getTouchingPointers(deviceId); sp<WindowInfoHandle> fromWindowHandle = touchedWindow->windowHandle; state->removeWindowByToken(fromToken); @@ -5481,7 +5492,8 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< if (canReceiveForegroundTouches(*toWindowHandle->getInfo())) { newTargetFlags |= InputTarget::Flags::FOREGROUND; } - state->addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds, downTimeInTarget); + state->addOrUpdateWindow(toWindowHandle, newTargetFlags, deviceId, pointerIds, + downTimeInTarget); // Store the dragging window. if (isDragDrop) { @@ -5500,16 +5512,15 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< std::shared_ptr<Connection> toConnection = getConnectionLocked(toToken); if (fromConnection != nullptr && toConnection != nullptr) { fromConnection->inputState.mergePointerStateTo(toConnection->inputState); - CancelationOptions - options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, - "transferring touch focus from this window to another window"); + CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, + "transferring touch from this window to another window"); synthesizeCancelationEventsForConnectionLocked(fromConnection, options); synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection, newTargetFlags); // Check if the wallpaper window should deliver the corresponding event. transferWallpaperTouch(oldTargetFlags, newTargetFlags, fromWindowHandle, toWindowHandle, - *state, pointerIds); + *state, deviceId, pointerIds); } } // release lock @@ -5993,20 +6004,28 @@ status_t InputDispatcher::pilferPointersLocked(const sp<IBinder>& token) { } auto [statePtr, windowPtr, displayId] = findTouchStateWindowAndDisplayLocked(token); - if (statePtr == nullptr || windowPtr == nullptr || windowPtr->pointerIds.none()) { + if (statePtr == nullptr || windowPtr == nullptr) { ALOGW("Attempted to pilfer points from a channel without any on-going pointer streams." " Ignoring."); return BAD_VALUE; } + std::set<int32_t> deviceIds = windowPtr->getTouchingDeviceIds(); + if (deviceIds.size() != 1) { + LOG(WARNING) << "Can't pilfer. Currently touching devices: " << dumpSet(deviceIds) + << " in window: " << windowPtr->dump(); + return BAD_VALUE; + } + const int32_t deviceId = *deviceIds.begin(); TouchState& state = *statePtr; TouchedWindow& window = *windowPtr; // Send cancel events to all the input channels we're stealing from. CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, "input channel stole pointer stream"); - options.deviceId = state.deviceId; + options.deviceId = deviceId; options.displayId = displayId; - options.pointerIds = window.pointerIds; + std::bitset<MAX_POINTER_ID + 1> pointerIds = window.getTouchingPointers(deviceId); + options.pointerIds = pointerIds; std::string canceledWindows; for (const TouchedWindow& w : state.windows) { const std::shared_ptr<InputChannel> channel = @@ -6023,9 +6042,9 @@ status_t InputDispatcher::pilferPointersLocked(const sp<IBinder>& token) { // Prevent the gesture from being sent to any other windows. // This only blocks relevant pointers to be sent to other windows - window.pilferedPointerIds |= window.pointerIds; + window.addPilferingPointers(deviceId, pointerIds); - state.cancelPointersForWindowsExcept(window.pointerIds, token); + state.cancelPointersForWindowsExcept(deviceId, pointerIds, token); return OK; } @@ -6812,7 +6831,7 @@ void InputDispatcher::setMonitorDispatchingTimeoutForTest(std::chrono::nanosecon void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, const sp<WindowInfoHandle>& oldWindowHandle, const sp<WindowInfoHandle>& newWindowHandle, - TouchState& state, int32_t pointerId, + TouchState& state, int32_t deviceId, int32_t pointerId, std::vector<InputTarget>& targets) const { std::bitset<MAX_POINTER_ID + 1> pointerIds; pointerIds.set(pointerId); @@ -6834,8 +6853,8 @@ void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFl addWindowTargetLocked(oldWallpaper, oldTouchedWindow.targetFlags | InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT, - pointerIds, oldTouchedWindow.firstDownTimeInTarget, targets); - state.removeTouchedPointerFromWindow(pointerId, oldWallpaper); + pointerIds, oldTouchedWindow.getDownTimeInTarget(deviceId), targets); + state.removeTouchingPointerFromWindow(deviceId, pointerId, oldWallpaper); } if (newWallpaper != nullptr) { @@ -6843,7 +6862,7 @@ void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFl InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER | InputTarget::Flags::WINDOW_IS_OBSCURED | InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED, - pointerIds); + deviceId, pointerIds); } } @@ -6851,7 +6870,7 @@ void InputDispatcher::transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldT ftl::Flags<InputTarget::Flags> newTargetFlags, const sp<WindowInfoHandle> fromWindowHandle, const sp<WindowInfoHandle> toWindowHandle, - TouchState& state, + TouchState& state, int32_t deviceId, std::bitset<MAX_POINTER_ID + 1> pointerIds) { const bool oldHasWallpaper = oldTargetFlags.test(InputTarget::Flags::FOREGROUND) && fromWindowHandle->getInfo()->inputConfig.test( @@ -6881,7 +6900,8 @@ void InputDispatcher::transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldT 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); + state.addOrUpdateWindow(newWallpaper, wallpaperFlags, deviceId, pointerIds, + downTimeInTarget); std::shared_ptr<Connection> wallpaperConnection = getConnectionLocked(newWallpaper->getToken()); if (wallpaperConnection != nullptr) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index cdce49214b..37f569ee97 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -711,14 +711,14 @@ private: void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, const sp<android::gui::WindowInfoHandle>& oldWindowHandle, const sp<android::gui::WindowInfoHandle>& newWindowHandle, - TouchState& state, int32_t pointerId, + TouchState& state, int32_t deviceId, int32_t pointerId, std::vector<InputTarget>& targets) const 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, std::bitset<MAX_POINTER_ID + 1> pointerIds) - REQUIRES(mLock); + TouchState& state, int32_t deviceId, + std::bitset<MAX_POINTER_ID + 1> pointerIds) REQUIRES(mLock); sp<android::gui::WindowInfoHandle> findWallpaperWindowBelow( const sp<android::gui::WindowInfoHandle>& windowHandle) const REQUIRES(mLock); diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index 0a61d48165..ef188c7844 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -31,18 +31,19 @@ void TouchState::reset() { *this = TouchState(); } -void TouchState::removeTouchedPointer(int32_t pointerId) { +void TouchState::removeTouchingPointer(int32_t removedDeviceId, int32_t pointerId) { for (TouchedWindow& touchedWindow : windows) { - touchedWindow.removeTouchingPointer(pointerId); + touchedWindow.removeTouchingPointer(removedDeviceId, pointerId); } clearWindowsWithoutPointers(); } -void TouchState::removeTouchedPointerFromWindow( - int32_t pointerId, const sp<android::gui::WindowInfoHandle>& windowHandle) { +void TouchState::removeTouchingPointerFromWindow( + int32_t removedDeviceId, int32_t pointerId, + const sp<android::gui::WindowInfoHandle>& windowHandle) { for (TouchedWindow& touchedWindow : windows) { if (touchedWindow.windowHandle == windowHandle) { - touchedWindow.removeTouchingPointer(pointerId); + touchedWindow.removeTouchingPointer(removedDeviceId, pointerId); clearWindowsWithoutPointers(); return; } @@ -58,13 +59,14 @@ void TouchState::clearHoveringPointers() { void TouchState::clearWindowsWithoutPointers() { std::erase_if(windows, [](const TouchedWindow& w) { - return w.pointerIds.none() && !w.hasHoveringPointers(); + return !w.hasTouchingPointers() && !w.hasHoveringPointers(); }); } void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, ftl::Flags<InputTarget::Flags> targetFlags, - std::bitset<MAX_POINTER_ID + 1> pointerIds, + int32_t addedDeviceId, + std::bitset<MAX_POINTER_ID + 1> touchingPointerIds, std::optional<nsecs_t> firstDownTimeInTarget) { for (TouchedWindow& touchedWindow : windows) { // We do not compare windows by token here because two windows that share the same token @@ -75,11 +77,11 @@ void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, touchedWindow.targetFlags.clear(InputTarget::Flags::DISPATCH_AS_IS); } // 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 an pointer is down for - // the window. - touchedWindow.pointerIds |= pointerIds; - if (!touchedWindow.firstDownTimeInTarget.has_value()) { - touchedWindow.firstDownTimeInTarget = firstDownTimeInTarget; + // downTime set initially. Need to update existing window when a pointer is down for the + // window. + touchedWindow.addTouchingPointers(addedDeviceId, touchingPointerIds); + if (firstDownTimeInTarget) { + touchedWindow.trySetDownTimeInTarget(addedDeviceId, *firstDownTimeInTarget); } return; } @@ -87,8 +89,10 @@ void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, TouchedWindow touchedWindow; touchedWindow.windowHandle = windowHandle; touchedWindow.targetFlags = targetFlags; - touchedWindow.pointerIds = pointerIds; - touchedWindow.firstDownTimeInTarget = firstDownTimeInTarget; + touchedWindow.addTouchingPointers(addedDeviceId, touchingPointerIds); + if (firstDownTimeInTarget) { + touchedWindow.trySetDownTimeInTarget(addedDeviceId, *firstDownTimeInTarget); + } windows.push_back(touchedWindow); } @@ -130,12 +134,12 @@ void TouchState::filterNonAsIsTouchWindows() { } } -void TouchState::cancelPointersForWindowsExcept(std::bitset<MAX_POINTER_ID + 1> pointerIds, +void TouchState::cancelPointersForWindowsExcept(int32_t touchedDeviceId, + std::bitset<MAX_POINTER_ID + 1> pointerIds, const sp<IBinder>& token) { - if (pointerIds.none()) return; - std::for_each(windows.begin(), windows.end(), [&pointerIds, &token](TouchedWindow& w) { + std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) { if (w.windowHandle->getToken() != token) { - w.pointerIds &= ~pointerIds; + w.removeTouchingPointers(touchedDeviceId, pointerIds); } }); clearWindowsWithoutPointers(); @@ -149,24 +153,29 @@ void TouchState::cancelPointersForWindowsExcept(std::bitset<MAX_POINTER_ID + 1> */ void TouchState::cancelPointersForNonPilferingWindows() { // First, find all pointers that are being pilfered, across all windows - std::bitset<MAX_POINTER_ID + 1> allPilferedPointerIds; - std::for_each(windows.begin(), windows.end(), [&allPilferedPointerIds](const TouchedWindow& w) { - allPilferedPointerIds |= w.pilferedPointerIds; - }); + std::map<int32_t /*deviceId*/, std::bitset<MAX_POINTER_ID + 1>> allPilferedPointerIdsByDevice; + for (const TouchedWindow& w : windows) { + for (const auto& [iterDeviceId, pilferedPointerIds] : w.getPilferingPointers()) { + allPilferedPointerIdsByDevice[iterDeviceId] |= pilferedPointerIds; + } + }; // Optimization: most of the time, pilfering does not occur - if (allPilferedPointerIds.none()) return; + if (allPilferedPointerIdsByDevice.empty()) return; // Now, remove all pointers from every window that's being pilfered by other windows. // For example, if window A is pilfering pointer 1 (only), and window B is pilfering pointer 2 // (only), the remove pointer 2 from window A and pointer 1 from window B. Usually, the set of // pilfered pointers will be disjoint across all windows, but there's no reason to cause that // limitation here. - std::for_each(windows.begin(), windows.end(), [&allPilferedPointerIds](TouchedWindow& w) { - std::bitset<MAX_POINTER_ID + 1> pilferedByOtherWindows = - w.pilferedPointerIds ^ allPilferedPointerIds; - w.pointerIds &= ~pilferedByOtherWindows; - }); + for (const auto& [iterDeviceId, allPilferedPointerIds] : allPilferedPointerIdsByDevice) { + std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) { + std::bitset<MAX_POINTER_ID + 1> pilferedByOtherWindows = + w.getPilferingPointers(iterDeviceId) ^ allPilferedPointerIds; + // Remove all pointers pilfered by other windows + w.removeTouchingPointers(iterDeviceId, pilferedByOtherWindows); + }); + } clearWindowsWithoutPointers(); } @@ -216,7 +225,7 @@ const TouchedWindow& TouchState::getTouchedWindow(const sp<WindowInfoHandle>& wi bool TouchState::isDown() const { return std::any_of(windows.begin(), windows.end(), - [](const TouchedWindow& window) { return window.pointerIds.any(); }); + [](const TouchedWindow& window) { return window.hasTouchingPointers(); }); } bool TouchState::hasHoveringPointers() const { @@ -245,12 +254,9 @@ void TouchState::removeHoveringPointer(int32_t hoveringDeviceId, int32_t hoverin void TouchState::removeAllPointersForDevice(int32_t removedDeviceId) { for (TouchedWindow& window : windows) { window.removeAllHoveringPointersForDevice(removedDeviceId); + window.removeAllTouchingPointersForDevice(removedDeviceId); } - if (deviceId == removedDeviceId) { - for (TouchedWindow& window : windows) { - window.removeAllTouchingPointers(); - } - } + clearWindowsWithoutPointers(); } diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 15b840f125..a2a9f75ef5 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -43,24 +43,25 @@ struct TouchState { void reset(); void clearWindowsWithoutPointers(); - void removeTouchedPointer(int32_t pointerId); - void removeTouchedPointerFromWindow(int32_t pointerId, - const sp<android::gui::WindowInfoHandle>& windowHandle); + void removeTouchingPointer(int32_t deviceId, int32_t pointerId); + void removeTouchingPointerFromWindow(int32_t deviceId, int32_t pointerId, + const sp<android::gui::WindowInfoHandle>& windowHandle); void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle, - ftl::Flags<InputTarget::Flags> targetFlags, - std::bitset<MAX_POINTER_ID + 1> pointerIds, + ftl::Flags<InputTarget::Flags> targetFlags, int32_t deviceId, + std::bitset<MAX_POINTER_ID + 1> touchingPointerIds, std::optional<nsecs_t> firstDownTimeInTarget = std::nullopt); void addHoveringPointerToWindow(const sp<android::gui::WindowInfoHandle>& windowHandle, int32_t deviceId, int32_t hoveringPointerId); void removeHoveringPointer(int32_t deviceId, int32_t hoveringPointerId); void clearHoveringPointers(); - void removeAllPointersForDevice(int32_t removedDeviceId); + void removeAllPointersForDevice(int32_t deviceId); void removeWindowByToken(const sp<IBinder>& token); void filterNonAsIsTouchWindows(); // Cancel pointers for current set of windows except the window with particular binder token. - void cancelPointersForWindowsExcept(std::bitset<MAX_POINTER_ID + 1> pointerIds, + void cancelPointersForWindowsExcept(int32_t deviceId, + std::bitset<MAX_POINTER_ID + 1> pointerIds, const sp<IBinder>& token); // Cancel pointers for current set of non-pilfering windows i.e. windows with isPilferingWindow // set to false. diff --git a/services/inputflinger/dispatcher/TouchedWindow.cpp b/services/inputflinger/dispatcher/TouchedWindow.cpp index d55d657667..6ab97f8ea5 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.cpp +++ b/services/inputflinger/dispatcher/TouchedWindow.cpp @@ -16,6 +16,7 @@ #include "TouchedWindow.h" +#include <android-base/logging.h> #include <android-base/stringprintf.h> #include <input/PrintTools.h> @@ -26,67 +27,228 @@ namespace android { namespace inputdispatcher { bool TouchedWindow::hasHoveringPointers() const { - return !mHoveringPointerIdsByDevice.empty(); + for (const auto& [_, state] : mDeviceStates) { + if (state.hoveringPointerIds.any()) { + return true; + } + } + return false; } bool TouchedWindow::hasHoveringPointers(int32_t deviceId) const { - return mHoveringPointerIdsByDevice.find(deviceId) != mHoveringPointerIdsByDevice.end(); + const auto stateIt = mDeviceStates.find(deviceId); + if (stateIt == mDeviceStates.end()) { + return false; + } + const DeviceState& state = stateIt->second; + + return state.hoveringPointerIds.any(); } void TouchedWindow::clearHoveringPointers() { - mHoveringPointerIdsByDevice.clear(); + for (auto& [_, state] : mDeviceStates) { + state.hoveringPointerIds.reset(); + } + + std::erase_if(mDeviceStates, [](const auto& pair) { return !pair.second.hasPointers(); }); } bool TouchedWindow::hasHoveringPointer(int32_t deviceId, int32_t pointerId) const { - auto it = mHoveringPointerIdsByDevice.find(deviceId); - if (it == mHoveringPointerIdsByDevice.end()) { + const auto stateIt = mDeviceStates.find(deviceId); + if (stateIt == mDeviceStates.end()) { return false; } - return it->second.test(pointerId); + const DeviceState& state = stateIt->second; + + return state.hoveringPointerIds.test(pointerId); } void TouchedWindow::addHoveringPointer(int32_t deviceId, int32_t pointerId) { - const auto [it, _] = mHoveringPointerIdsByDevice.insert({deviceId, {}}); - it->second.set(pointerId); + mDeviceStates[deviceId].hoveringPointerIds.set(pointerId); +} + +void TouchedWindow::addTouchingPointer(int32_t deviceId, int32_t pointerId) { + mDeviceStates[deviceId].touchingPointerIds.set(pointerId); } -void TouchedWindow::removeTouchingPointer(int32_t pointerId) { - pointerIds.reset(pointerId); - pilferedPointerIds.reset(pointerId); - if (pointerIds.none()) { - firstDownTimeInTarget.reset(); +void TouchedWindow::addTouchingPointers(int32_t deviceId, + std::bitset<MAX_POINTER_ID + 1> pointers) { + mDeviceStates[deviceId].touchingPointerIds |= pointers; +} + +bool TouchedWindow::hasTouchingPointers() const { + for (const auto& [_, state] : mDeviceStates) { + if (state.touchingPointerIds.any()) { + return true; + } } + return false; } -void TouchedWindow::removeAllTouchingPointers() { - pointerIds.reset(); +bool TouchedWindow::hasTouchingPointers(int32_t deviceId) const { + return getTouchingPointers(deviceId).any(); +} + +bool TouchedWindow::hasTouchingPointer(int32_t deviceId, int32_t pointerId) const { + return getTouchingPointers(deviceId).test(pointerId); +} + +std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getTouchingPointers(int32_t deviceId) const { + const auto stateIt = mDeviceStates.find(deviceId); + if (stateIt == mDeviceStates.end()) { + return {}; + } + const DeviceState& state = stateIt->second; + + return state.touchingPointerIds; +} + +void TouchedWindow::removeTouchingPointer(int32_t deviceId, int32_t pointerId) { + std::bitset<MAX_POINTER_ID + 1> pointerIds; + pointerIds.set(pointerId, true); + + removeTouchingPointers(deviceId, pointerIds); +} + +void TouchedWindow::removeTouchingPointers(int32_t deviceId, + std::bitset<MAX_POINTER_ID + 1> pointers) { + const auto stateIt = mDeviceStates.find(deviceId); + if (stateIt == mDeviceStates.end()) { + return; + } + DeviceState& state = stateIt->second; + + state.touchingPointerIds &= ~pointers; + state.pilferingPointerIds &= ~pointers; + + if (!state.hasPointers()) { + mDeviceStates.erase(stateIt); + } +} + +std::set<int32_t> TouchedWindow::getTouchingDeviceIds() const { + std::set<int32_t> deviceIds; + for (const auto& [deviceId, _] : mDeviceStates) { + deviceIds.insert(deviceId); + } + return deviceIds; +} + +bool TouchedWindow::hasPilferingPointers(int32_t deviceId) const { + const auto stateIt = mDeviceStates.find(deviceId); + if (stateIt == mDeviceStates.end()) { + return false; + } + const DeviceState& state = stateIt->second; + + return state.pilferingPointerIds.any(); +} + +void TouchedWindow::addPilferingPointers(int32_t deviceId, + std::bitset<MAX_POINTER_ID + 1> pointerIds) { + mDeviceStates[deviceId].pilferingPointerIds |= pointerIds; +} + +void TouchedWindow::addPilferingPointer(int32_t deviceId, int32_t pointerId) { + mDeviceStates[deviceId].pilferingPointerIds.set(pointerId); +} + +std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getPilferingPointers(int32_t deviceId) const { + const auto stateIt = mDeviceStates.find(deviceId); + if (stateIt == mDeviceStates.end()) { + return {}; + } + const DeviceState& state = stateIt->second; + + return state.pilferingPointerIds; +} + +std::map<int32_t, std::bitset<MAX_POINTER_ID + 1>> TouchedWindow::getPilferingPointers() const { + std::map<int32_t, std::bitset<MAX_POINTER_ID + 1>> out; + for (const auto& [deviceId, state] : mDeviceStates) { + out.emplace(deviceId, state.pilferingPointerIds); + } + return out; +} + +std::optional<nsecs_t> TouchedWindow::getDownTimeInTarget(int32_t deviceId) const { + const auto stateIt = mDeviceStates.find(deviceId); + if (stateIt == mDeviceStates.end()) { + return {}; + } + const DeviceState& state = stateIt->second; + return state.downTimeInTarget; +} + +void TouchedWindow::trySetDownTimeInTarget(int32_t deviceId, nsecs_t downTime) { + auto [stateIt, _] = mDeviceStates.try_emplace(deviceId); + DeviceState& state = stateIt->second; + + if (!state.downTimeInTarget) { + state.downTimeInTarget = downTime; + } +} + +void TouchedWindow::removeAllTouchingPointersForDevice(int32_t deviceId) { + const auto stateIt = mDeviceStates.find(deviceId); + if (stateIt == mDeviceStates.end()) { + return; + } + DeviceState& state = stateIt->second; + + state.touchingPointerIds.reset(); + state.pilferingPointerIds.reset(); + state.downTimeInTarget.reset(); + + if (!state.hasPointers()) { + mDeviceStates.erase(stateIt); + } } void TouchedWindow::removeHoveringPointer(int32_t deviceId, int32_t pointerId) { - const auto it = mHoveringPointerIdsByDevice.find(deviceId); - if (it == mHoveringPointerIdsByDevice.end()) { + const auto stateIt = mDeviceStates.find(deviceId); + if (stateIt == mDeviceStates.end()) { return; } - it->second.set(pointerId, false); + DeviceState& state = stateIt->second; - if (it->second.none()) { - mHoveringPointerIdsByDevice.erase(deviceId); + state.hoveringPointerIds.set(pointerId, false); + + if (!state.hasPointers()) { + mDeviceStates.erase(stateIt); } } void TouchedWindow::removeAllHoveringPointersForDevice(int32_t deviceId) { - mHoveringPointerIdsByDevice.erase(deviceId); + const auto stateIt = mDeviceStates.find(deviceId); + if (stateIt == mDeviceStates.end()) { + return; + } + DeviceState& state = stateIt->second; + + state.hoveringPointerIds.reset(); + + if (!state.hasPointers()) { + mDeviceStates.erase(stateIt); + } +} + +std::string TouchedWindow::deviceStateToString(const TouchedWindow::DeviceState& state) { + return StringPrintf("[touchingPointerIds=%s, " + "downTimeInTarget=%s, hoveringPointerIds=%s, pilferingPointerIds=%s]", + bitsetToString(state.touchingPointerIds).c_str(), + toString(state.downTimeInTarget).c_str(), + bitsetToString(state.hoveringPointerIds).c_str(), + bitsetToString(state.pilferingPointerIds).c_str()); } std::string TouchedWindow::dump() const { std::string out; - std::string hoveringPointers = - dumpMap(mHoveringPointerIdsByDevice, constToString, bitsetToString); - out += StringPrintf("name='%s', pointerIds=%s, targetFlags=%s, firstDownTimeInTarget=%s, " - "mHoveringPointerIdsByDevice=%s, pilferedPointerIds=%s\n", - windowHandle->getName().c_str(), bitsetToString(pointerIds).c_str(), - targetFlags.string().c_str(), toString(firstDownTimeInTarget).c_str(), - hoveringPointers.c_str(), bitsetToString(pilferedPointerIds).c_str()); + std::string deviceStates = + dumpMap(mDeviceStates, constToString, TouchedWindow::deviceStateToString); + out += StringPrintf("name='%s', targetFlags=%s, mDeviceStates=%s\n", + windowHandle->getName().c_str(), targetFlags.string().c_str(), + deviceStates.c_str()); return out; } diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h index 43e716973c..e50ede50b6 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.h +++ b/services/inputflinger/dispatcher/TouchedWindow.h @@ -20,6 +20,7 @@ #include <input/Input.h> #include <utils/BitSet.h> #include <bitset> +#include <set> #include "InputTarget.h" namespace android { @@ -30,28 +31,62 @@ namespace inputdispatcher { struct TouchedWindow { sp<gui::WindowInfoHandle> windowHandle; ftl::Flags<InputTarget::Flags> targetFlags; - std::bitset<MAX_POINTER_ID + 1> pointerIds; - // The pointer ids of the pointers that this window is currently pilfering - std::bitset<MAX_POINTER_ID + 1> pilferedPointerIds; - // Time at which the first action down occurred on this window. - // NOTE: This is not initialized in case of HOVER entry/exit and DISPATCH_AS_OUTSIDE scenario. - std::optional<nsecs_t> firstDownTimeInTarget; + // Hovering bool hasHoveringPointers() const; bool hasHoveringPointers(int32_t deviceId) const; - bool hasHoveringPointer(int32_t deviceId, int32_t pointerId) const; void addHoveringPointer(int32_t deviceId, int32_t pointerId); void removeHoveringPointer(int32_t deviceId, int32_t pointerId); - void removeTouchingPointer(int32_t pointerId); - void removeAllTouchingPointers(); + // Touching + bool hasTouchingPointer(int32_t deviceId, int32_t pointerId) const; + bool hasTouchingPointers() const; + bool hasTouchingPointers(int32_t deviceId) const; + std::bitset<MAX_POINTER_ID + 1> getTouchingPointers(int32_t deviceId) const; + void addTouchingPointer(int32_t deviceId, int32_t pointerId); + void addTouchingPointers(int32_t deviceId, std::bitset<MAX_POINTER_ID + 1> pointers); + void removeTouchingPointer(int32_t deviceId, int32_t pointerId); + void removeTouchingPointers(int32_t deviceId, std::bitset<MAX_POINTER_ID + 1> pointers); + /** + * Get the currently active touching device id. If there isn't exactly 1 touching device, return + * nullopt. + */ + std::set<int32_t> getTouchingDeviceIds() const; + + // Pilfering pointers + bool hasPilferingPointers(int32_t deviceId) const; + void addPilferingPointers(int32_t deviceId, std::bitset<MAX_POINTER_ID + 1> pointerIds); + void addPilferingPointer(int32_t deviceId, int32_t pointerId); + std::bitset<MAX_POINTER_ID + 1> getPilferingPointers(int32_t deviceId) const; + std::map<int32_t, std::bitset<MAX_POINTER_ID + 1>> getPilferingPointers() const; + + // Down time + std::optional<nsecs_t> getDownTimeInTarget(int32_t deviceId) const; + void trySetDownTimeInTarget(int32_t deviceId, nsecs_t downTime); + + void removeAllTouchingPointersForDevice(int32_t deviceId); void removeAllHoveringPointersForDevice(int32_t deviceId); void clearHoveringPointers(); std::string dump() const; private: - std::map<int32_t /*deviceId*/, std::bitset<MAX_POINTER_ID + 1>> mHoveringPointerIdsByDevice; + struct DeviceState { + std::bitset<MAX_POINTER_ID + 1> touchingPointerIds; + // The pointer ids of the pointers that this window is currently pilfering, by device + std::bitset<MAX_POINTER_ID + 1> pilferingPointerIds; + // Time at which the first action down occurred on this window, for each device + // NOTE: This is not initialized in case of HOVER entry/exit and DISPATCH_AS_OUTSIDE + // scenario. + std::optional<nsecs_t> downTimeInTarget; + std::bitset<MAX_POINTER_ID + 1> hoveringPointerIds; + + bool hasPointers() const { return touchingPointerIds.any() || hoveringPointerIds.any(); }; + }; + + std::map<int32_t /*deviceId*/, DeviceState> mDeviceStates; + + static std::string deviceStateToString(const TouchedWindow::DeviceState& state); }; } // namespace inputdispatcher |