summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp254
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.h32
2 files changed, 214 insertions, 72 deletions
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 9efe74de6c..bc2904e0ba 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -165,6 +165,8 @@ constexpr int LOGTAG_INPUT_INTERACTION = 62000;
constexpr int LOGTAG_INPUT_FOCUS = 62001;
constexpr int LOGTAG_INPUT_CANCEL = 62003;
+static const bool USE_TOPOLOGY = com::android::input::flags::connected_displays_cursor();
+
const ui::Transform kIdentityTransform;
inline nsecs_t now() {
@@ -919,6 +921,13 @@ std::string dumpWindowForTouchOcclusion(const WindowInfo& info, bool isTouchedWi
binderToString(info.applicationInfo.token).c_str());
}
+bool isMouseOrTouchpad(uint32_t sources) {
+ // Check if this is a mouse or touchpad, but not a drawing tablet.
+ return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) ||
+ (isFromSource(sources, AINPUT_SOURCE_MOUSE) &&
+ !isFromSource(sources, AINPUT_SOURCE_STYLUS));
+}
+
} // namespace
// --- InputDispatcher ---
@@ -2387,12 +2396,11 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets(
const int32_t maskedAction = MotionEvent::getActionMasked(action);
// Copy current touch state into tempTouchState.
- // This state will be used to update mTouchStatesByDisplay at the end of this function.
+ // This state will be used to update saved touch state at the end of this function.
// If no state for the specified display exists, then our initial state will be empty.
- const TouchState* oldState = nullptr;
+ const TouchState* oldState = getTouchStateForMotionEntry(entry);
TouchState tempTouchState;
- if (const auto it = mTouchStatesByDisplay.find(displayId); it != mTouchStatesByDisplay.end()) {
- oldState = &(it->second);
+ if (oldState != nullptr) {
tempTouchState = *oldState;
}
@@ -2779,16 +2787,12 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets(
if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) {
if (displayId >= ui::LogicalDisplayId::DEFAULT) {
tempTouchState.clearWindowsWithoutPointers();
- mTouchStatesByDisplay[displayId] = tempTouchState;
+ saveTouchStateForMotionEntry(entry, std::move(tempTouchState));
} else {
- mTouchStatesByDisplay.erase(displayId);
+ eraseTouchStateForMotionEntry(entry);
}
}
- if (tempTouchState.windows.empty()) {
- mTouchStatesByDisplay.erase(displayId);
- }
-
return targets;
}
@@ -5439,12 +5443,13 @@ std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>
InputDispatcher::DispatcherTouchState::updateFromWindowInfo(
ui::LogicalDisplayId displayId, const DispatcherWindowInfo& windowInfos) {
std::list<CancellationArgs> cancellations;
- if (const auto& it = mTouchStatesByDisplay.find(displayId); it != mTouchStatesByDisplay.end()) {
- TouchState& state = it->second;
- cancellations = eraseRemovedWindowsFromWindowInfo(state, displayId, windowInfos);
+ forTouchAndCursorStatesOnDisplay(displayId, [&](TouchState& state) {
+ cancellations.splice(cancellations.end(),
+ eraseRemovedWindowsFromWindowInfo(state, displayId, windowInfos));
cancellations.splice(cancellations.end(),
updateHoveringStateFromWindowInfo(state, displayId, windowInfos));
- }
+ return false;
+ });
return cancellations;
}
@@ -5866,26 +5871,25 @@ InputDispatcher::DispatcherTouchState::transferTouchGesture(const sp<android::IB
*/
sp<WindowInfoHandle> InputDispatcher::DispatcherTouchState::findTouchedForegroundWindow(
ui::LogicalDisplayId displayId) const {
- const auto stateIt = mTouchStatesByDisplay.find(displayId);
- if (stateIt == mTouchStatesByDisplay.end()) {
- ALOGI("No touch state on display %s", displayId.toString().c_str());
- return nullptr;
- }
-
- const TouchState& state = stateIt->second;
sp<WindowInfoHandle> touchedForegroundWindow;
- // If multiple foreground windows are touched, return nullptr
- for (const TouchedWindow& window : state.windows) {
- if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
- if (touchedForegroundWindow != nullptr) {
- ALOGI("Two or more foreground windows: %s and %s",
- touchedForegroundWindow->getName().c_str(),
- window.windowHandle->getName().c_str());
- return nullptr;
+ forTouchAndCursorStatesOnDisplay(displayId, [&](const TouchState& state) {
+ // If multiple foreground windows are touched, return nullptr
+ for (const TouchedWindow& window : state.windows) {
+ if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
+ if (touchedForegroundWindow != nullptr) {
+ ALOGI("Two or more foreground windows: %s and %s",
+ touchedForegroundWindow->getName().c_str(),
+ window.windowHandle->getName().c_str());
+ touchedForegroundWindow = nullptr;
+ return true;
+ }
+ touchedForegroundWindow = window.windowHandle;
}
- touchedForegroundWindow = window.windowHandle;
}
- }
+ return false;
+ });
+ ALOGI_IF(touchedForegroundWindow == nullptr,
+ "No touch state or no touched foreground window on display %d", displayId.val());
return touchedForegroundWindow;
}
@@ -7366,101 +7370,209 @@ ftl::Flags<InputTarget::Flags> InputDispatcher::DispatcherTouchState::getTargetF
bool InputDispatcher::DispatcherTouchState::hasTouchingOrHoveringPointers(
ui::LogicalDisplayId displayId, int32_t deviceId) const {
- const auto touchStateIt = mTouchStatesByDisplay.find(displayId);
- if (touchStateIt == mTouchStatesByDisplay.end()) {
- return false;
- }
- return touchStateIt->second.hasTouchingPointers(deviceId) ||
- touchStateIt->second.hasHoveringPointers(deviceId);
+ bool hasTouchingOrHoveringPointers = false;
+ forTouchAndCursorStatesOnDisplay(displayId, [&](const TouchState& state) {
+ hasTouchingOrHoveringPointers =
+ state.hasTouchingPointers(deviceId) || state.hasHoveringPointers(deviceId);
+ return hasTouchingOrHoveringPointers;
+ });
+ return hasTouchingOrHoveringPointers;
}
bool InputDispatcher::DispatcherTouchState::isPointerInWindow(const sp<android::IBinder>& token,
ui::LogicalDisplayId displayId,
android::DeviceId deviceId,
int32_t pointerId) const {
- const auto touchStateIt = mTouchStatesByDisplay.find(displayId);
- if (touchStateIt == mTouchStatesByDisplay.end()) {
- return false;
- }
- for (const TouchedWindow& window : touchStateIt->second.windows) {
- if (window.windowHandle->getToken() == token &&
- (window.hasTouchingPointer(deviceId, pointerId) ||
- window.hasHoveringPointer(deviceId, pointerId))) {
- return true;
+ bool isPointerInWindow = false;
+ forTouchAndCursorStatesOnDisplay(displayId, [&](const TouchState& state) {
+ for (const TouchedWindow& window : state.windows) {
+ if (window.windowHandle->getToken() == token &&
+ (window.hasTouchingPointer(deviceId, pointerId) ||
+ window.hasHoveringPointer(deviceId, pointerId))) {
+ isPointerInWindow = true;
+ return true;
+ }
}
- }
- return false;
+ return false;
+ });
+ return isPointerInWindow;
}
std::tuple<const sp<gui::WindowInfoHandle>&, ui::LogicalDisplayId>
InputDispatcher::DispatcherTouchState::findExistingTouchedWindowHandleAndDisplay(
const sp<android::IBinder>& token) const {
- for (const auto& [displayId, state] : mTouchStatesByDisplay) {
+ std::optional<std::tuple<const sp<gui::WindowInfoHandle>&, ui::LogicalDisplayId>>
+ touchedWindowHandleAndDisplay;
+ forAllTouchAndCursorStates([&](ui::LogicalDisplayId displayId, const TouchState& state) {
for (const TouchedWindow& w : state.windows) {
if (w.windowHandle->getToken() == token) {
- return std::make_tuple(std::ref(w.windowHandle), displayId);
+ touchedWindowHandleAndDisplay.emplace(std::ref(w.windowHandle), displayId);
+ return true;
}
}
- }
- LOG_ALWAYS_FATAL("%s : Touch state is out of sync: No touched window for token", __func__);
+ return false;
+ });
+ LOG_ALWAYS_FATAL_IF(!touchedWindowHandleAndDisplay.has_value(),
+ "%s : Touch state is out of sync: No touched window for token", __func__);
+ return touchedWindowHandleAndDisplay.value();
}
void InputDispatcher::DispatcherTouchState::forAllTouchedWindows(
std::function<void(const sp<gui::WindowInfoHandle>&)> f) const {
- for (const auto& [_, state] : mTouchStatesByDisplay) {
+ forAllTouchAndCursorStates([&](ui::LogicalDisplayId displayId, const TouchState& state) {
for (const TouchedWindow& window : state.windows) {
f(window.windowHandle);
}
- }
+ return false;
+ });
}
void InputDispatcher::DispatcherTouchState::forAllTouchedWindowsOnDisplay(
ui::LogicalDisplayId displayId,
std::function<void(const sp<gui::WindowInfoHandle>&)> f) const {
- const auto touchStateIt = mTouchStatesByDisplay.find(displayId);
- if (touchStateIt == mTouchStatesByDisplay.end()) {
- return;
- }
- for (const TouchedWindow& window : touchStateIt->second.windows) {
- f(window.windowHandle);
- }
+ forTouchAndCursorStatesOnDisplay(displayId, [&](const TouchState& state) {
+ for (const TouchedWindow& window : state.windows) {
+ f(window.windowHandle);
+ }
+ return false;
+ });
}
std::string InputDispatcher::DispatcherTouchState::dump() const {
std::string dump;
- if (!mTouchStatesByDisplay.empty()) {
- dump += StringPrintf("TouchStatesByDisplay:\n");
+ if (mTouchStatesByDisplay.empty()) {
+ dump += "TouchStatesByDisplay: <no displays touched>\n";
+ } else {
+ dump += "TouchStatesByDisplay:\n";
for (const auto& [displayId, state] : mTouchStatesByDisplay) {
std::string touchStateDump = addLinePrefix(state.dump(), INDENT);
dump += INDENT + displayId.toString() + " : " + touchStateDump;
}
+ }
+ if (mCursorStateByDisplay.empty()) {
+ dump += "CursorStatesByDisplay: <no displays touched by cursor>\n";
} else {
- dump += "TouchStates: <no displays touched>\n";
+ dump += "CursorStatesByDisplay:\n";
+ for (const auto& [displayId, state] : mCursorStateByDisplay) {
+ std::string touchStateDump = addLinePrefix(state.dump(), INDENT);
+ dump += INDENT + displayId.toString() + " : " + touchStateDump;
+ }
}
return dump;
}
void InputDispatcher::DispatcherTouchState::removeAllPointersForDevice(android::DeviceId deviceId) {
- for (auto& [_, touchState] : mTouchStatesByDisplay) {
- touchState.removeAllPointersForDevice(deviceId);
- }
+ forAllTouchAndCursorStates([&](ui::LogicalDisplayId displayId, TouchState& state) {
+ state.removeAllPointersForDevice(deviceId);
+ return false;
+ });
}
void InputDispatcher::DispatcherTouchState::clear() {
mTouchStatesByDisplay.clear();
+ mCursorStateByDisplay.clear();
+}
+
+void InputDispatcher::DispatcherTouchState::saveTouchStateForMotionEntry(
+ const android::inputdispatcher::MotionEntry& entry,
+ android::inputdispatcher::TouchState&& touchState) {
+ if (touchState.windows.empty()) {
+ eraseTouchStateForMotionEntry(entry);
+ return;
+ }
+
+ if (USE_TOPOLOGY && isMouseOrTouchpad(entry.source)) {
+ mCursorStateByDisplay[entry.displayId] = std::move(touchState);
+ } else {
+ mTouchStatesByDisplay[entry.displayId] = std::move(touchState);
+ }
+}
+
+void InputDispatcher::DispatcherTouchState::eraseTouchStateForMotionEntry(
+ const android::inputdispatcher::MotionEntry& entry) {
+ if (USE_TOPOLOGY && isMouseOrTouchpad(entry.source)) {
+ mCursorStateByDisplay.erase(entry.displayId);
+ } else {
+ mTouchStatesByDisplay.erase(entry.displayId);
+ }
+}
+
+const TouchState* InputDispatcher::DispatcherTouchState::getTouchStateForMotionEntry(
+ const android::inputdispatcher::MotionEntry& entry) const {
+ if (USE_TOPOLOGY && isMouseOrTouchpad(entry.source)) {
+ auto touchStateIt = mCursorStateByDisplay.find(entry.displayId);
+ if (touchStateIt != mCursorStateByDisplay.end()) {
+ return &touchStateIt->second;
+ }
+ } else {
+ auto touchStateIt = mTouchStatesByDisplay.find(entry.displayId);
+ if (touchStateIt != mTouchStatesByDisplay.end()) {
+ return &touchStateIt->second;
+ }
+ }
+ return nullptr;
+}
+
+void InputDispatcher::DispatcherTouchState::forTouchAndCursorStatesOnDisplay(
+ ui::LogicalDisplayId displayId, std::function<bool(const TouchState&)> f) const {
+ const auto touchStateIt = mTouchStatesByDisplay.find(displayId);
+ if (touchStateIt != mTouchStatesByDisplay.end() && f(touchStateIt->second)) {
+ return;
+ }
+
+ // TODO(b/383092013): This is currently not accounting for the "topology group" concept.
+ // Proper implementation requires looking tghrough all the displays in the topology group.
+ const auto cursorStateIt = mCursorStateByDisplay.find(displayId);
+ if (cursorStateIt != mCursorStateByDisplay.end()) {
+ f(cursorStateIt->second);
+ }
+}
+
+void InputDispatcher::DispatcherTouchState::forTouchAndCursorStatesOnDisplay(
+ ui::LogicalDisplayId displayId, std::function<bool(TouchState&)> f) {
+ const_cast<const DispatcherTouchState&>(*this)
+ .forTouchAndCursorStatesOnDisplay(displayId, [&](const TouchState& state) {
+ return f(const_cast<TouchState&>(state));
+ });
+}
+
+void InputDispatcher::DispatcherTouchState::forAllTouchAndCursorStates(
+ std::function<bool(ui::LogicalDisplayId, const TouchState&)> f) const {
+ for (auto& [displayId, state] : mTouchStatesByDisplay) {
+ if (f(displayId, state)) {
+ return;
+ }
+ }
+ for (auto& [displayId, state] : mCursorStateByDisplay) {
+ if (f(displayId, state)) {
+ return;
+ }
+ }
+}
+
+void InputDispatcher::DispatcherTouchState::forAllTouchAndCursorStates(
+ std::function<bool(ui::LogicalDisplayId, TouchState&)> f) {
+ const_cast<const DispatcherTouchState&>(*this).forAllTouchAndCursorStates(
+ [&](ui::LogicalDisplayId displayId, const TouchState& constState) {
+ return f(displayId, const_cast<TouchState&>(constState));
+ });
}
std::optional<std::tuple<TouchState&, TouchedWindow&, ui::LogicalDisplayId>>
InputDispatcher::DispatcherTouchState::findTouchStateWindowAndDisplay(
const sp<android::IBinder>& token) {
- for (auto& [displayId, state] : mTouchStatesByDisplay) {
+ std::optional<std::tuple<TouchState&, TouchedWindow&, ui::LogicalDisplayId>>
+ touchStateWindowAndDisplay;
+ forAllTouchAndCursorStates([&](ui::LogicalDisplayId displayId, TouchState& state) {
for (TouchedWindow& w : state.windows) {
if (w.windowHandle->getToken() == token) {
- return std::make_tuple(std::ref(state), std::ref(w), displayId);
+ touchStateWindowAndDisplay.emplace(std::ref(state), std::ref(w), displayId);
+ return true;
}
}
- }
- return std::nullopt;
+ return false;
+ });
+ return touchStateWindowAndDisplay;
}
bool InputDispatcher::DispatcherTouchState::isStylusActiveInDisplay(
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index db7ebfd4e3..c2224de106 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -432,6 +432,29 @@ private:
private:
std::unordered_map<ui::LogicalDisplayId, TouchState> mTouchStatesByDisplay;
+ // As there can be only one CursorState per topology group, we will treat all displays in
+ // the topology as one connected display-group. These will be identified by
+ // DisplayTopologyGraph::primaryDisplayId.
+ // Cursor on the any of the displays that are not part of the topology will be identified by
+ // the displayId similar to mTouchStatesByDisplay.
+ std::unordered_map<ui::LogicalDisplayId, TouchState> mCursorStateByDisplay;
+
+ // The supplied lambda is invoked for each touch and cursor state of the display.
+ // The function iterates until the lambda returns true, effectively performing a 'break'
+ // from the iteration.
+ void forTouchAndCursorStatesOnDisplay(ui::LogicalDisplayId displayId,
+ std::function<bool(const TouchState&)> f) const;
+
+ void forTouchAndCursorStatesOnDisplay(ui::LogicalDisplayId displayId,
+ std::function<bool(TouchState&)> f);
+
+ // The supplied lambda is invoked for each touchState. The function iterates until
+ // the lambda returns true, effectively performing a 'break' from the iteration.
+ void forAllTouchAndCursorStates(
+ std::function<bool(ui::LogicalDisplayId, const TouchState&)> f) const;
+
+ void forAllTouchAndCursorStates(std::function<bool(ui::LogicalDisplayId, TouchState&)> f);
+
std::optional<std::tuple<TouchState&, TouchedWindow&, ui::LogicalDisplayId>>
findTouchStateWindowAndDisplay(const sp<IBinder>& token);
@@ -443,7 +466,14 @@ private:
ftl::Flags<InputTarget::Flags> newTargetFlags,
const DispatcherWindowInfo& windowInfos, const ConnectionManager& connections);
- bool canWindowReceiveMotion(const sp<android::gui::WindowInfoHandle>& window,
+ void saveTouchStateForMotionEntry(const MotionEntry& entry, TouchState&& touchState);
+
+ void eraseTouchStateForMotionEntry(const MotionEntry& entry);
+
+ const TouchState* getTouchStateForMotionEntry(
+ const android::inputdispatcher::MotionEntry& entry) const;
+
+ bool canWindowReceiveMotion(const sp<gui::WindowInfoHandle>& window,
const MotionEntry& motionEntry,
const ConnectionManager& connections,
const DispatcherWindowInfo& windowInfos) const;