Skip to content

Commit 96efbfe

Browse files
author
Arpit Singh
committed
[2/n CD Cursor] Introduce cursor State
Introduce Cursor State as mCursorStateByDisplay. This will be used to store and track TouchState for devices that control the mouse cursor. In upcoming CLs we will use this state to allow mouse-cursor based gestures to continue across connected-displays based on topology. Bug: 367661487 Test: atest inputflinger_tests Test: adb shell setprop persist.device_config.aconfig_flags.\ lse_desktop_experience.com.android.input.flags.\ connected_displays_cursor true && atest inputflinger_tests Flag: com.android.input.flags.connected_displays_cursor Change-Id: Iabe980cb6f7f6314bfe2f53e8f3b842d5b2c1529
1 parent 5783824 commit 96efbfe

2 files changed

Lines changed: 214 additions & 72 deletions

File tree

services/inputflinger/dispatcher/InputDispatcher.cpp

Lines changed: 183 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ constexpr int LOGTAG_INPUT_INTERACTION = 62000;
165165
constexpr int LOGTAG_INPUT_FOCUS = 62001;
166166
constexpr int LOGTAG_INPUT_CANCEL = 62003;
167167

168+
static const bool USE_TOPOLOGY = com::android::input::flags::connected_displays_cursor();
169+
168170
const ui::Transform kIdentityTransform;
169171

170172
inline nsecs_t now() {
@@ -919,6 +921,13 @@ std::string dumpWindowForTouchOcclusion(const WindowInfo& info, bool isTouchedWi
919921
binderToString(info.applicationInfo.token).c_str());
920922
}
921923

924+
bool isMouseOrTouchpad(uint32_t sources) {
925+
// Check if this is a mouse or touchpad, but not a drawing tablet.
926+
return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) ||
927+
(isFromSource(sources, AINPUT_SOURCE_MOUSE) &&
928+
!isFromSource(sources, AINPUT_SOURCE_STYLUS));
929+
}
930+
922931
} // namespace
923932

924933
// --- InputDispatcher ---
@@ -2387,12 +2396,11 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets(
23872396
const int32_t maskedAction = MotionEvent::getActionMasked(action);
23882397

23892398
// Copy current touch state into tempTouchState.
2390-
// This state will be used to update mTouchStatesByDisplay at the end of this function.
2399+
// This state will be used to update saved touch state at the end of this function.
23912400
// If no state for the specified display exists, then our initial state will be empty.
2392-
const TouchState* oldState = nullptr;
2401+
const TouchState* oldState = getTouchStateForMotionEntry(entry);
23932402
TouchState tempTouchState;
2394-
if (const auto it = mTouchStatesByDisplay.find(displayId); it != mTouchStatesByDisplay.end()) {
2395-
oldState = &(it->second);
2403+
if (oldState != nullptr) {
23962404
tempTouchState = *oldState;
23972405
}
23982406

@@ -2779,16 +2787,12 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets(
27792787
if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) {
27802788
if (displayId >= ui::LogicalDisplayId::DEFAULT) {
27812789
tempTouchState.clearWindowsWithoutPointers();
2782-
mTouchStatesByDisplay[displayId] = tempTouchState;
2790+
saveTouchStateForMotionEntry(entry, std::move(tempTouchState));
27832791
} else {
2784-
mTouchStatesByDisplay.erase(displayId);
2792+
eraseTouchStateForMotionEntry(entry);
27852793
}
27862794
}
27872795

2788-
if (tempTouchState.windows.empty()) {
2789-
mTouchStatesByDisplay.erase(displayId);
2790-
}
2791-
27922796
return targets;
27932797
}
27942798

@@ -5439,12 +5443,13 @@ std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>
54395443
InputDispatcher::DispatcherTouchState::updateFromWindowInfo(
54405444
ui::LogicalDisplayId displayId, const DispatcherWindowInfo& windowInfos) {
54415445
std::list<CancellationArgs> cancellations;
5442-
if (const auto& it = mTouchStatesByDisplay.find(displayId); it != mTouchStatesByDisplay.end()) {
5443-
TouchState& state = it->second;
5444-
cancellations = eraseRemovedWindowsFromWindowInfo(state, displayId, windowInfos);
5446+
forTouchAndCursorStatesOnDisplay(displayId, [&](TouchState& state) {
5447+
cancellations.splice(cancellations.end(),
5448+
eraseRemovedWindowsFromWindowInfo(state, displayId, windowInfos));
54455449
cancellations.splice(cancellations.end(),
54465450
updateHoveringStateFromWindowInfo(state, displayId, windowInfos));
5447-
}
5451+
return false;
5452+
});
54485453
return cancellations;
54495454
}
54505455

@@ -5866,26 +5871,25 @@ InputDispatcher::DispatcherTouchState::transferTouchGesture(const sp<android::IB
58665871
*/
58675872
sp<WindowInfoHandle> InputDispatcher::DispatcherTouchState::findTouchedForegroundWindow(
58685873
ui::LogicalDisplayId displayId) const {
5869-
const auto stateIt = mTouchStatesByDisplay.find(displayId);
5870-
if (stateIt == mTouchStatesByDisplay.end()) {
5871-
ALOGI("No touch state on display %s", displayId.toString().c_str());
5872-
return nullptr;
5873-
}
5874-
5875-
const TouchState& state = stateIt->second;
58765874
sp<WindowInfoHandle> touchedForegroundWindow;
5877-
// If multiple foreground windows are touched, return nullptr
5878-
for (const TouchedWindow& window : state.windows) {
5879-
if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
5880-
if (touchedForegroundWindow != nullptr) {
5881-
ALOGI("Two or more foreground windows: %s and %s",
5882-
touchedForegroundWindow->getName().c_str(),
5883-
window.windowHandle->getName().c_str());
5884-
return nullptr;
5875+
forTouchAndCursorStatesOnDisplay(displayId, [&](const TouchState& state) {
5876+
// If multiple foreground windows are touched, return nullptr
5877+
for (const TouchedWindow& window : state.windows) {
5878+
if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
5879+
if (touchedForegroundWindow != nullptr) {
5880+
ALOGI("Two or more foreground windows: %s and %s",
5881+
touchedForegroundWindow->getName().c_str(),
5882+
window.windowHandle->getName().c_str());
5883+
touchedForegroundWindow = nullptr;
5884+
return true;
5885+
}
5886+
touchedForegroundWindow = window.windowHandle;
58855887
}
5886-
touchedForegroundWindow = window.windowHandle;
58875888
}
5888-
}
5889+
return false;
5890+
});
5891+
ALOGI_IF(touchedForegroundWindow == nullptr,
5892+
"No touch state or no touched foreground window on display %d", displayId.val());
58895893
return touchedForegroundWindow;
58905894
}
58915895

@@ -7366,101 +7370,209 @@ ftl::Flags<InputTarget::Flags> InputDispatcher::DispatcherTouchState::getTargetF
73667370

73677371
bool InputDispatcher::DispatcherTouchState::hasTouchingOrHoveringPointers(
73687372
ui::LogicalDisplayId displayId, int32_t deviceId) const {
7369-
const auto touchStateIt = mTouchStatesByDisplay.find(displayId);
7370-
if (touchStateIt == mTouchStatesByDisplay.end()) {
7371-
return false;
7372-
}
7373-
return touchStateIt->second.hasTouchingPointers(deviceId) ||
7374-
touchStateIt->second.hasHoveringPointers(deviceId);
7373+
bool hasTouchingOrHoveringPointers = false;
7374+
forTouchAndCursorStatesOnDisplay(displayId, [&](const TouchState& state) {
7375+
hasTouchingOrHoveringPointers =
7376+
state.hasTouchingPointers(deviceId) || state.hasHoveringPointers(deviceId);
7377+
return hasTouchingOrHoveringPointers;
7378+
});
7379+
return hasTouchingOrHoveringPointers;
73757380
}
73767381

73777382
bool InputDispatcher::DispatcherTouchState::isPointerInWindow(const sp<android::IBinder>& token,
73787383
ui::LogicalDisplayId displayId,
73797384
android::DeviceId deviceId,
73807385
int32_t pointerId) const {
7381-
const auto touchStateIt = mTouchStatesByDisplay.find(displayId);
7382-
if (touchStateIt == mTouchStatesByDisplay.end()) {
7383-
return false;
7384-
}
7385-
for (const TouchedWindow& window : touchStateIt->second.windows) {
7386-
if (window.windowHandle->getToken() == token &&
7387-
(window.hasTouchingPointer(deviceId, pointerId) ||
7388-
window.hasHoveringPointer(deviceId, pointerId))) {
7389-
return true;
7386+
bool isPointerInWindow = false;
7387+
forTouchAndCursorStatesOnDisplay(displayId, [&](const TouchState& state) {
7388+
for (const TouchedWindow& window : state.windows) {
7389+
if (window.windowHandle->getToken() == token &&
7390+
(window.hasTouchingPointer(deviceId, pointerId) ||
7391+
window.hasHoveringPointer(deviceId, pointerId))) {
7392+
isPointerInWindow = true;
7393+
return true;
7394+
}
73907395
}
7391-
}
7392-
return false;
7396+
return false;
7397+
});
7398+
return isPointerInWindow;
73937399
}
73947400

73957401
std::tuple<const sp<gui::WindowInfoHandle>&, ui::LogicalDisplayId>
73967402
InputDispatcher::DispatcherTouchState::findExistingTouchedWindowHandleAndDisplay(
73977403
const sp<android::IBinder>& token) const {
7398-
for (const auto& [displayId, state] : mTouchStatesByDisplay) {
7404+
std::optional<std::tuple<const sp<gui::WindowInfoHandle>&, ui::LogicalDisplayId>>
7405+
touchedWindowHandleAndDisplay;
7406+
forAllTouchAndCursorStates([&](ui::LogicalDisplayId displayId, const TouchState& state) {
73997407
for (const TouchedWindow& w : state.windows) {
74007408
if (w.windowHandle->getToken() == token) {
7401-
return std::make_tuple(std::ref(w.windowHandle), displayId);
7409+
touchedWindowHandleAndDisplay.emplace(std::ref(w.windowHandle), displayId);
7410+
return true;
74027411
}
74037412
}
7404-
}
7405-
LOG_ALWAYS_FATAL("%s : Touch state is out of sync: No touched window for token", __func__);
7413+
return false;
7414+
});
7415+
LOG_ALWAYS_FATAL_IF(!touchedWindowHandleAndDisplay.has_value(),
7416+
"%s : Touch state is out of sync: No touched window for token", __func__);
7417+
return touchedWindowHandleAndDisplay.value();
74067418
}
74077419

74087420
void InputDispatcher::DispatcherTouchState::forAllTouchedWindows(
74097421
std::function<void(const sp<gui::WindowInfoHandle>&)> f) const {
7410-
for (const auto& [_, state] : mTouchStatesByDisplay) {
7422+
forAllTouchAndCursorStates([&](ui::LogicalDisplayId displayId, const TouchState& state) {
74117423
for (const TouchedWindow& window : state.windows) {
74127424
f(window.windowHandle);
74137425
}
7414-
}
7426+
return false;
7427+
});
74157428
}
74167429

74177430
void InputDispatcher::DispatcherTouchState::forAllTouchedWindowsOnDisplay(
74187431
ui::LogicalDisplayId displayId,
74197432
std::function<void(const sp<gui::WindowInfoHandle>&)> f) const {
7420-
const auto touchStateIt = mTouchStatesByDisplay.find(displayId);
7421-
if (touchStateIt == mTouchStatesByDisplay.end()) {
7422-
return;
7423-
}
7424-
for (const TouchedWindow& window : touchStateIt->second.windows) {
7425-
f(window.windowHandle);
7426-
}
7433+
forTouchAndCursorStatesOnDisplay(displayId, [&](const TouchState& state) {
7434+
for (const TouchedWindow& window : state.windows) {
7435+
f(window.windowHandle);
7436+
}
7437+
return false;
7438+
});
74277439
}
74287440

74297441
std::string InputDispatcher::DispatcherTouchState::dump() const {
74307442
std::string dump;
7431-
if (!mTouchStatesByDisplay.empty()) {
7432-
dump += StringPrintf("TouchStatesByDisplay:\n");
7443+
if (mTouchStatesByDisplay.empty()) {
7444+
dump += "TouchStatesByDisplay: <no displays touched>\n";
7445+
} else {
7446+
dump += "TouchStatesByDisplay:\n";
74337447
for (const auto& [displayId, state] : mTouchStatesByDisplay) {
74347448
std::string touchStateDump = addLinePrefix(state.dump(), INDENT);
74357449
dump += INDENT + displayId.toString() + " : " + touchStateDump;
74367450
}
7451+
}
7452+
if (mCursorStateByDisplay.empty()) {
7453+
dump += "CursorStatesByDisplay: <no displays touched by cursor>\n";
74377454
} else {
7438-
dump += "TouchStates: <no displays touched>\n";
7455+
dump += "CursorStatesByDisplay:\n";
7456+
for (const auto& [displayId, state] : mCursorStateByDisplay) {
7457+
std::string touchStateDump = addLinePrefix(state.dump(), INDENT);
7458+
dump += INDENT + displayId.toString() + " : " + touchStateDump;
7459+
}
74397460
}
74407461
return dump;
74417462
}
74427463

74437464
void InputDispatcher::DispatcherTouchState::removeAllPointersForDevice(android::DeviceId deviceId) {
7444-
for (auto& [_, touchState] : mTouchStatesByDisplay) {
7445-
touchState.removeAllPointersForDevice(deviceId);
7446-
}
7465+
forAllTouchAndCursorStates([&](ui::LogicalDisplayId displayId, TouchState& state) {
7466+
state.removeAllPointersForDevice(deviceId);
7467+
return false;
7468+
});
74477469
}
74487470

74497471
void InputDispatcher::DispatcherTouchState::clear() {
74507472
mTouchStatesByDisplay.clear();
7473+
mCursorStateByDisplay.clear();
7474+
}
7475+
7476+
void InputDispatcher::DispatcherTouchState::saveTouchStateForMotionEntry(
7477+
const android::inputdispatcher::MotionEntry& entry,
7478+
android::inputdispatcher::TouchState&& touchState) {
7479+
if (touchState.windows.empty()) {
7480+
eraseTouchStateForMotionEntry(entry);
7481+
return;
7482+
}
7483+
7484+
if (USE_TOPOLOGY && isMouseOrTouchpad(entry.source)) {
7485+
mCursorStateByDisplay[entry.displayId] = std::move(touchState);
7486+
} else {
7487+
mTouchStatesByDisplay[entry.displayId] = std::move(touchState);
7488+
}
7489+
}
7490+
7491+
void InputDispatcher::DispatcherTouchState::eraseTouchStateForMotionEntry(
7492+
const android::inputdispatcher::MotionEntry& entry) {
7493+
if (USE_TOPOLOGY && isMouseOrTouchpad(entry.source)) {
7494+
mCursorStateByDisplay.erase(entry.displayId);
7495+
} else {
7496+
mTouchStatesByDisplay.erase(entry.displayId);
7497+
}
7498+
}
7499+
7500+
const TouchState* InputDispatcher::DispatcherTouchState::getTouchStateForMotionEntry(
7501+
const android::inputdispatcher::MotionEntry& entry) const {
7502+
if (USE_TOPOLOGY && isMouseOrTouchpad(entry.source)) {
7503+
auto touchStateIt = mCursorStateByDisplay.find(entry.displayId);
7504+
if (touchStateIt != mCursorStateByDisplay.end()) {
7505+
return &touchStateIt->second;
7506+
}
7507+
} else {
7508+
auto touchStateIt = mTouchStatesByDisplay.find(entry.displayId);
7509+
if (touchStateIt != mTouchStatesByDisplay.end()) {
7510+
return &touchStateIt->second;
7511+
}
7512+
}
7513+
return nullptr;
7514+
}
7515+
7516+
void InputDispatcher::DispatcherTouchState::forTouchAndCursorStatesOnDisplay(
7517+
ui::LogicalDisplayId displayId, std::function<bool(const TouchState&)> f) const {
7518+
const auto touchStateIt = mTouchStatesByDisplay.find(displayId);
7519+
if (touchStateIt != mTouchStatesByDisplay.end() && f(touchStateIt->second)) {
7520+
return;
7521+
}
7522+
7523+
// TODO(b/383092013): This is currently not accounting for the "topology group" concept.
7524+
// Proper implementation requires looking tghrough all the displays in the topology group.
7525+
const auto cursorStateIt = mCursorStateByDisplay.find(displayId);
7526+
if (cursorStateIt != mCursorStateByDisplay.end()) {
7527+
f(cursorStateIt->second);
7528+
}
7529+
}
7530+
7531+
void InputDispatcher::DispatcherTouchState::forTouchAndCursorStatesOnDisplay(
7532+
ui::LogicalDisplayId displayId, std::function<bool(TouchState&)> f) {
7533+
const_cast<const DispatcherTouchState&>(*this)
7534+
.forTouchAndCursorStatesOnDisplay(displayId, [&](const TouchState& state) {
7535+
return f(const_cast<TouchState&>(state));
7536+
});
7537+
}
7538+
7539+
void InputDispatcher::DispatcherTouchState::forAllTouchAndCursorStates(
7540+
std::function<bool(ui::LogicalDisplayId, const TouchState&)> f) const {
7541+
for (auto& [displayId, state] : mTouchStatesByDisplay) {
7542+
if (f(displayId, state)) {
7543+
return;
7544+
}
7545+
}
7546+
for (auto& [displayId, state] : mCursorStateByDisplay) {
7547+
if (f(displayId, state)) {
7548+
return;
7549+
}
7550+
}
7551+
}
7552+
7553+
void InputDispatcher::DispatcherTouchState::forAllTouchAndCursorStates(
7554+
std::function<bool(ui::LogicalDisplayId, TouchState&)> f) {
7555+
const_cast<const DispatcherTouchState&>(*this).forAllTouchAndCursorStates(
7556+
[&](ui::LogicalDisplayId displayId, const TouchState& constState) {
7557+
return f(displayId, const_cast<TouchState&>(constState));
7558+
});
74517559
}
74527560

74537561
std::optional<std::tuple<TouchState&, TouchedWindow&, ui::LogicalDisplayId>>
74547562
InputDispatcher::DispatcherTouchState::findTouchStateWindowAndDisplay(
74557563
const sp<android::IBinder>& token) {
7456-
for (auto& [displayId, state] : mTouchStatesByDisplay) {
7564+
std::optional<std::tuple<TouchState&, TouchedWindow&, ui::LogicalDisplayId>>
7565+
touchStateWindowAndDisplay;
7566+
forAllTouchAndCursorStates([&](ui::LogicalDisplayId displayId, TouchState& state) {
74577567
for (TouchedWindow& w : state.windows) {
74587568
if (w.windowHandle->getToken() == token) {
7459-
return std::make_tuple(std::ref(state), std::ref(w), displayId);
7569+
touchStateWindowAndDisplay.emplace(std::ref(state), std::ref(w), displayId);
7570+
return true;
74607571
}
74617572
}
7462-
}
7463-
return std::nullopt;
7573+
return false;
7574+
});
7575+
return touchStateWindowAndDisplay;
74647576
}
74657577

74667578
bool InputDispatcher::DispatcherTouchState::isStylusActiveInDisplay(

0 commit comments

Comments
 (0)