Loading services/inputflinger/dispatcher/InputDispatcher.cpp +20 −9 Original line number Diff line number Diff line Loading @@ -2333,14 +2333,22 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( } } // If any existing window is pilfering pointers from newly added window, remove it BitSet32 canceledPointers = BitSet32(0); for (const TouchedWindow& window : tempTouchState.windows) { if (window.isPilferingPointers) { canceledPointers |= window.pointerIds; } } tempTouchState.cancelPointersForNonPilferingWindows(canceledPointers); // If a window is already pilfering some pointers, give it this new pointer as well and // make it pilfering. This will prevent other non-spy windows from getting this pointer, // which is a specific behaviour that we want. const int32_t pointerId = entry.pointerProperties[pointerIndex].id; for (TouchedWindow& touchedWindow : tempTouchState.windows) { if (touchedWindow.pointerIds.hasBit(pointerId) && touchedWindow.pilferedPointerIds.count() > 0) { // 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); } } // Restrict all pilfered pointers to the pilfering windows. tempTouchState.cancelPointersForNonPilferingWindows(); } else { /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ Loading Loading @@ -3942,8 +3950,8 @@ std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent( if (action == AMOTION_EVENT_ACTION_DOWN) { LOG_ALWAYS_FATAL_IF(splitDownTime != originalMotionEntry.eventTime, "Split motion event has mismatching downTime and eventTime for " "ACTION_DOWN, motionEntry=%s, splitDownTime=%" PRId64 "ms", originalMotionEntry.getDescription().c_str(), ns2ms(splitDownTime)); "ACTION_DOWN, motionEntry=%s, splitDownTime=%" PRId64, originalMotionEntry.getDescription().c_str(), splitDownTime); } int32_t newId = mIdGenerator.nextId(); Loading Loading @@ -5778,7 +5786,10 @@ 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.isPilferingPointers = true; for (BitSet32 idBits(window.pointerIds); !idBits.isEmpty();) { uint32_t id = idBits.clearFirstMarkedBit(); window.pilferedPointerIds.set(id); } state.cancelPointersForWindowsExcept(window.pointerIds, token); return OK; Loading services/inputflinger/dispatcher/TouchState.cpp +36 −5 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ void TouchState::reset() { void TouchState::removeTouchedPointer(int32_t pointerId) { for (TouchedWindow& touchedWindow : windows) { touchedWindow.pointerIds.clearBit(pointerId); touchedWindow.pilferedPointerIds.reset(pointerId); } } Loading @@ -42,6 +43,7 @@ void TouchState::removeTouchedPointerFromWindow( for (TouchedWindow& touchedWindow : windows) { if (touchedWindow.windowHandle == windowHandle) { touchedWindow.pointerIds.clearBit(pointerId); touchedWindow.pilferedPointerIds.reset(pointerId); return; } } Loading Loading @@ -137,11 +139,40 @@ void TouchState::cancelPointersForWindowsExcept(const BitSet32 pointerIds, std::erase_if(windows, [](const TouchedWindow& w) { return w.pointerIds.isEmpty(); }); } void TouchState::cancelPointersForNonPilferingWindows(const BitSet32 pointerIds) { if (pointerIds.isEmpty()) return; std::for_each(windows.begin(), windows.end(), [&pointerIds](TouchedWindow& w) { if (!w.isPilferingPointers) { w.pointerIds &= BitSet32(~pointerIds.value); /** * For any pointer that's being pilfered, remove it from all of the other windows that currently * aren't pilfering it. For example, if we determined that pointer 1 is going to both window A and * window B, but window A is currently pilfering pointer 1, then pointer 1 should not go to window * B. */ void TouchState::cancelPointersForNonPilferingWindows() { // First, find all pointers that are being pilfered, across all windows std::bitset<MAX_POINTERS> allPilferedPointerIds; std::for_each(windows.begin(), windows.end(), [&allPilferedPointerIds](const TouchedWindow& w) { allPilferedPointerIds |= w.pilferedPointerIds; }); // Optimization: most of the time, pilfering does not occur if (allPilferedPointerIds.none()) 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_POINTERS> pilferedByOtherWindows = w.pilferedPointerIds ^ allPilferedPointerIds; // TODO(b/211379801) : convert pointerIds to use std::bitset, which would allow us to // replace the loop below with a bitwise operation. Currently, the XOR operation above is // redundant, but is done to make the code more explicit / easier to convert later. for (std::size_t i = 0; i < pilferedByOtherWindows.size(); i++) { if (pilferedByOtherWindows.test(i) && !w.pilferedPointerIds.test(i)) { // Pointer is pilfered by other windows, but not by this one! Remove it from here. // We could call 'removeTouchedPointerFromWindow' here, but it's faster to directly // manipulate it. w.pointerIds.clearBit(i); } } }); std::erase_if(windows, [](const TouchedWindow& w) { return w.pointerIds.isEmpty(); }); Loading services/inputflinger/dispatcher/TouchState.h +1 −1 Original line number Diff line number Diff line Loading @@ -59,7 +59,7 @@ struct TouchState { void cancelPointersForWindowsExcept(const BitSet32 pointerIds, const sp<IBinder>& token); // Cancel pointers for current set of non-pilfering windows i.e. windows with isPilferingWindow // set to false. void cancelPointersForNonPilferingWindows(const BitSet32 pointerIds); void cancelPointersForNonPilferingWindows(); sp<android::gui::WindowInfoHandle> getFirstForegroundWindowHandle() const; bool isSlippery() const; Loading services/inputflinger/dispatcher/TouchedWindow.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -63,10 +63,10 @@ std::string TouchedWindow::dump() const { std::string hoveringPointers = dumpMap(mHoveringPointerIdsByDevice, constToString, bitsetToString); out += StringPrintf("name='%s', pointerIds=0x%0x, targetFlags=%s, firstDownTimeInTarget=%s, " "mHoveringPointerIdsByDevice=%s\n", "mHoveringPointerIdsByDevice=%s, pilferedPointerIds=%s\n", windowHandle->getName().c_str(), pointerIds.value, targetFlags.string().c_str(), toString(firstDownTimeInTarget).c_str(), hoveringPointers.c_str()); hoveringPointers.c_str(), bitsetToString(pilferedPointerIds).c_str()); return out; } Loading services/inputflinger/dispatcher/TouchedWindow.h +2 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,8 @@ struct TouchedWindow { sp<gui::WindowInfoHandle> windowHandle; ftl::Flags<InputTarget::Flags> targetFlags; BitSet32 pointerIds; bool isPilferingPointers = false; // The pointer ids of the pointers that this window is currently pilfering std::bitset<MAX_POINTERS> 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; Loading Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +20 −9 Original line number Diff line number Diff line Loading @@ -2333,14 +2333,22 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( } } // If any existing window is pilfering pointers from newly added window, remove it BitSet32 canceledPointers = BitSet32(0); for (const TouchedWindow& window : tempTouchState.windows) { if (window.isPilferingPointers) { canceledPointers |= window.pointerIds; } } tempTouchState.cancelPointersForNonPilferingWindows(canceledPointers); // If a window is already pilfering some pointers, give it this new pointer as well and // make it pilfering. This will prevent other non-spy windows from getting this pointer, // which is a specific behaviour that we want. const int32_t pointerId = entry.pointerProperties[pointerIndex].id; for (TouchedWindow& touchedWindow : tempTouchState.windows) { if (touchedWindow.pointerIds.hasBit(pointerId) && touchedWindow.pilferedPointerIds.count() > 0) { // 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); } } // Restrict all pilfered pointers to the pilfering windows. tempTouchState.cancelPointersForNonPilferingWindows(); } else { /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ Loading Loading @@ -3942,8 +3950,8 @@ std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent( if (action == AMOTION_EVENT_ACTION_DOWN) { LOG_ALWAYS_FATAL_IF(splitDownTime != originalMotionEntry.eventTime, "Split motion event has mismatching downTime and eventTime for " "ACTION_DOWN, motionEntry=%s, splitDownTime=%" PRId64 "ms", originalMotionEntry.getDescription().c_str(), ns2ms(splitDownTime)); "ACTION_DOWN, motionEntry=%s, splitDownTime=%" PRId64, originalMotionEntry.getDescription().c_str(), splitDownTime); } int32_t newId = mIdGenerator.nextId(); Loading Loading @@ -5778,7 +5786,10 @@ 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.isPilferingPointers = true; for (BitSet32 idBits(window.pointerIds); !idBits.isEmpty();) { uint32_t id = idBits.clearFirstMarkedBit(); window.pilferedPointerIds.set(id); } state.cancelPointersForWindowsExcept(window.pointerIds, token); return OK; Loading
services/inputflinger/dispatcher/TouchState.cpp +36 −5 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ void TouchState::reset() { void TouchState::removeTouchedPointer(int32_t pointerId) { for (TouchedWindow& touchedWindow : windows) { touchedWindow.pointerIds.clearBit(pointerId); touchedWindow.pilferedPointerIds.reset(pointerId); } } Loading @@ -42,6 +43,7 @@ void TouchState::removeTouchedPointerFromWindow( for (TouchedWindow& touchedWindow : windows) { if (touchedWindow.windowHandle == windowHandle) { touchedWindow.pointerIds.clearBit(pointerId); touchedWindow.pilferedPointerIds.reset(pointerId); return; } } Loading Loading @@ -137,11 +139,40 @@ void TouchState::cancelPointersForWindowsExcept(const BitSet32 pointerIds, std::erase_if(windows, [](const TouchedWindow& w) { return w.pointerIds.isEmpty(); }); } void TouchState::cancelPointersForNonPilferingWindows(const BitSet32 pointerIds) { if (pointerIds.isEmpty()) return; std::for_each(windows.begin(), windows.end(), [&pointerIds](TouchedWindow& w) { if (!w.isPilferingPointers) { w.pointerIds &= BitSet32(~pointerIds.value); /** * For any pointer that's being pilfered, remove it from all of the other windows that currently * aren't pilfering it. For example, if we determined that pointer 1 is going to both window A and * window B, but window A is currently pilfering pointer 1, then pointer 1 should not go to window * B. */ void TouchState::cancelPointersForNonPilferingWindows() { // First, find all pointers that are being pilfered, across all windows std::bitset<MAX_POINTERS> allPilferedPointerIds; std::for_each(windows.begin(), windows.end(), [&allPilferedPointerIds](const TouchedWindow& w) { allPilferedPointerIds |= w.pilferedPointerIds; }); // Optimization: most of the time, pilfering does not occur if (allPilferedPointerIds.none()) 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_POINTERS> pilferedByOtherWindows = w.pilferedPointerIds ^ allPilferedPointerIds; // TODO(b/211379801) : convert pointerIds to use std::bitset, which would allow us to // replace the loop below with a bitwise operation. Currently, the XOR operation above is // redundant, but is done to make the code more explicit / easier to convert later. for (std::size_t i = 0; i < pilferedByOtherWindows.size(); i++) { if (pilferedByOtherWindows.test(i) && !w.pilferedPointerIds.test(i)) { // Pointer is pilfered by other windows, but not by this one! Remove it from here. // We could call 'removeTouchedPointerFromWindow' here, but it's faster to directly // manipulate it. w.pointerIds.clearBit(i); } } }); std::erase_if(windows, [](const TouchedWindow& w) { return w.pointerIds.isEmpty(); }); Loading
services/inputflinger/dispatcher/TouchState.h +1 −1 Original line number Diff line number Diff line Loading @@ -59,7 +59,7 @@ struct TouchState { void cancelPointersForWindowsExcept(const BitSet32 pointerIds, const sp<IBinder>& token); // Cancel pointers for current set of non-pilfering windows i.e. windows with isPilferingWindow // set to false. void cancelPointersForNonPilferingWindows(const BitSet32 pointerIds); void cancelPointersForNonPilferingWindows(); sp<android::gui::WindowInfoHandle> getFirstForegroundWindowHandle() const; bool isSlippery() const; Loading
services/inputflinger/dispatcher/TouchedWindow.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -63,10 +63,10 @@ std::string TouchedWindow::dump() const { std::string hoveringPointers = dumpMap(mHoveringPointerIdsByDevice, constToString, bitsetToString); out += StringPrintf("name='%s', pointerIds=0x%0x, targetFlags=%s, firstDownTimeInTarget=%s, " "mHoveringPointerIdsByDevice=%s\n", "mHoveringPointerIdsByDevice=%s, pilferedPointerIds=%s\n", windowHandle->getName().c_str(), pointerIds.value, targetFlags.string().c_str(), toString(firstDownTimeInTarget).c_str(), hoveringPointers.c_str()); hoveringPointers.c_str(), bitsetToString(pilferedPointerIds).c_str()); return out; } Loading
services/inputflinger/dispatcher/TouchedWindow.h +2 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,8 @@ struct TouchedWindow { sp<gui::WindowInfoHandle> windowHandle; ftl::Flags<InputTarget::Flags> targetFlags; BitSet32 pointerIds; bool isPilferingPointers = false; // The pointer ids of the pointers that this window is currently pilfering std::bitset<MAX_POINTERS> 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; Loading