Add concept of gesture input monitors.
Bug: 123748692
Test: manual
Change-Id: I2abd90b622ef5d7461c783ef17fabd941103228e
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 0d5bc15..abdecd9 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "InputDispatcher"
#define ATRACE_TAG ATRACE_TAG_INPUT
-//#define LOG_NDEBUG 0
+#define LOG_NDEBUG 0
// Log detailed debug messages about each inbound event notification to the dispatcher.
#define DEBUG_INBOUND_EVENT_DETAILS 0
@@ -58,7 +58,6 @@
#include <log/log.h>
#include <utils/Trace.h>
#include <powermanager/PowerManager.h>
-#include <ui/Region.h>
#include <binder/Binder.h>
#define INDENT " "
@@ -129,7 +128,7 @@
static std::string keyActionToString(int32_t action) {
// Convert KeyEvent action to string
- switch(action) {
+ switch (action) {
case AKEY_EVENT_ACTION_DOWN:
return "DOWN";
case AKEY_EVENT_ACTION_UP:
@@ -140,6 +139,24 @@
return StringPrintf("%" PRId32, action);
}
+static std::string dispatchModeToString(int32_t dispatchMode) {
+ switch (dispatchMode) {
+ case InputTarget::FLAG_DISPATCH_AS_IS:
+ return "DISPATCH_AS_IS";
+ case InputTarget::FLAG_DISPATCH_AS_OUTSIDE:
+ return "DISPATCH_AS_OUTSIDE";
+ case InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER:
+ return "DISPATCH_AS_HOVER_ENTER";
+ case InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT:
+ return "DISPATCH_AS_HOVER_EXIT";
+ case InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT:
+ return "DISPATCH_AS_SLIPPERY_EXIT";
+ case InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER:
+ return "DISPATCH_AS_SLIPPERY_ENTER";
+ }
+ return StringPrintf("%" PRId32, dispatchMode);
+}
+
static inline int32_t getMotionEventActionPointerIndex(int32_t action) {
return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
>> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
@@ -560,6 +577,32 @@
return nullptr;
}
+std::vector<InputDispatcher::TouchedMonitor> InputDispatcher::findTouchedGestureMonitorsLocked(
+ int32_t displayId, const std::vector<sp<InputWindowHandle>>& portalWindows) {
+ std::vector<TouchedMonitor> touchedMonitors;
+
+ std::vector<Monitor> monitors = getValueByKey(mGestureMonitorsByDisplay, displayId);
+ addGestureMonitors(monitors, touchedMonitors);
+ for (const sp<InputWindowHandle>& portalWindow : portalWindows) {
+ const InputWindowInfo* windowInfo = portalWindow->getInfo();
+ monitors = getValueByKey(mGestureMonitorsByDisplay, windowInfo->portalToDisplayId);
+ addGestureMonitors(monitors, touchedMonitors,
+ -windowInfo->frameLeft, -windowInfo->frameTop);
+ }
+ return touchedMonitors;
+}
+
+void InputDispatcher::addGestureMonitors(const std::vector<Monitor>& monitors,
+ std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset, float yOffset) {
+ if (monitors.empty()) {
+ return;
+ }
+ outTouchedMonitors.reserve(monitors.size() + outTouchedMonitors.size());
+ for (const Monitor& monitor : monitors) {
+ outTouchedMonitors.emplace_back(monitor, xOffset, yOffset);
+ }
+}
+
void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) {
const char* reason;
switch (dropReason) {
@@ -870,7 +913,7 @@
}
// Add monitor channels from event's or focused display.
- addMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));
+ addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));
// Dispatch the key.
dispatchEventLocked(currentTime, entry, inputTargets);
@@ -891,6 +934,7 @@
bool InputDispatcher::dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
+ ATRACE_CALL();
// Preprocessing.
if (! entry->dispatchInProgress) {
entry->dispatchInProgress = true;
@@ -938,7 +982,7 @@
}
// Add monitor channels from event's or focused display.
- addMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));
+ addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));
if (isPointerEvent) {
ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(entry->displayId);
@@ -949,7 +993,7 @@
// the corresponding displays as well.
for (size_t i = 0; i < state.portalWindows.size(); i++) {
const InputWindowInfo* windowInfo = state.portalWindows[i]->getInfo();
- addMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId,
+ addGlobalMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId,
-windowInfo->frameLeft, -windowInfo->frameTop);
}
}
@@ -1003,6 +1047,7 @@
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const std::vector<InputTarget>& inputTargets) {
+ ATRACE_CALL();
#if DEBUG_DISPATCH_CYCLE
ALOGD("dispatchEventToCurrentInputTargets");
#endif
@@ -1242,6 +1287,7 @@
int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
const MotionEntry* entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
bool* outConflictingPointerActions) {
+ ATRACE_CALL();
enum InjectionPermission {
INJECTION_PERMISSION_UNKNOWN,
INJECTION_PERMISSION_GRANTED,
@@ -1320,8 +1366,13 @@
getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = int32_t(entry->pointerCoords[pointerIndex].
getAxisValue(AMOTION_EVENT_AXIS_Y));
+ bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN;
sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked(
- displayId, x, y, maskedAction == AMOTION_EVENT_ACTION_DOWN, true);
+ displayId, x, y, isDown /*addOutsideTargets*/, true /*addPortalWindows*/);
+
+ std::vector<TouchedMonitor> newGestureMonitors = isDown
+ ? findTouchedGestureMonitorsLocked(displayId, mTempTouchState.portalWindows)
+ : std::vector<TouchedMonitor>{};
// Figure out whether splitting will be allowed for this window.
if (newTouchedWindowHandle != nullptr
@@ -1338,39 +1389,44 @@
if (newTouchedWindowHandle == nullptr) {
// Try to assign the pointer to the first foreground window we find, if there is one.
newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle();
- if (newTouchedWindowHandle == nullptr) {
- ALOGI("Dropping event because there is no touchable window at (%d, %d) in display "
- "%" PRId32 ".", x, y, displayId);
- injectionResult = INPUT_EVENT_INJECTION_FAILED;
- goto Failed;
+ }
+
+ if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) {
+ ALOGI("Dropping event because there is no touchable window or gesture monitor at "
+ "(%d, %d) in display %" PRId32 ".", x, y, displayId);
+ injectionResult = INPUT_EVENT_INJECTION_FAILED;
+ goto Failed;
+ }
+
+ if (newTouchedWindowHandle != nullptr) {
+ // Set target flags.
+ int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS;
+ if (isSplit) {
+ targetFlags |= InputTarget::FLAG_SPLIT;
}
+ if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
+ targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
+ } else if (isWindowObscuredLocked(newTouchedWindowHandle)) {
+ targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+ }
+
+ // Update hover state.
+ if (isHoverAction) {
+ newHoverWindowHandle = newTouchedWindowHandle;
+ } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) {
+ newHoverWindowHandle = mLastHoverWindowHandle;
+ }
+
+ // Update the temporary touch state.
+ BitSet32 pointerIds;
+ if (isSplit) {
+ uint32_t pointerId = entry->pointerProperties[pointerIndex].id;
+ pointerIds.markBit(pointerId);
+ }
+ mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
}
- // Set target flags.
- int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS;
- if (isSplit) {
- targetFlags |= InputTarget::FLAG_SPLIT;
- }
- if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
- targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
- } else if (isWindowObscuredLocked(newTouchedWindowHandle)) {
- targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
- }
-
- // Update hover state.
- if (isHoverAction) {
- newHoverWindowHandle = newTouchedWindowHandle;
- } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) {
- newHoverWindowHandle = mLastHoverWindowHandle;
- }
-
- // Update the temporary touch state.
- BitSet32 pointerIds;
- if (isSplit) {
- uint32_t pointerId = entry->pointerProperties[pointerIndex].id;
- pointerIds.markBit(pointerId);
- }
- mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
+ mTempTouchState.addGestureMonitors(newGestureMonitors);
} else {
/* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
@@ -1396,6 +1452,7 @@
sp<InputWindowHandle> newTouchedWindowHandle =
findTouchedWindowAtLocked(displayId, x, y);
if (oldTouchedWindowHandle != newTouchedWindowHandle
+ && oldTouchedWindowHandle != nullptr
&& newTouchedWindowHandle != nullptr) {
#if DEBUG_FOCUS
ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32,
@@ -1467,10 +1524,11 @@
}
}
}
- if (! haveForegroundWindow) {
+ bool hasGestureMonitor = !mTempTouchState.gestureMonitors.empty();
+ if (!haveForegroundWindow && !hasGestureMonitor) {
#if DEBUG_FOCUS
- ALOGD("Dropping event because there is no touched foreground window in display %" PRId32
- " to receive it.", displayId);
+ ALOGD("Dropping event because there is no touched foreground window in display %"
+ PRId32 " or gesture monitor to receive it.", displayId);
#endif
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
@@ -1485,13 +1543,15 @@
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
sp<InputWindowHandle> foregroundWindowHandle =
mTempTouchState.getFirstForegroundWindowHandle();
- const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;
- for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {
- if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
- sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle;
- if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) {
- mTempTouchState.addOrUpdateWindow(inputWindowHandle,
- InputTarget::FLAG_ZERO_COORDS, BitSet32(0));
+ if (foregroundWindowHandle) {
+ const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;
+ for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {
+ if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
+ sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle;
+ if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) {
+ mTempTouchState.addOrUpdateWindow(inputWindowHandle,
+ InputTarget::FLAG_ZERO_COORDS, BitSet32(0));
+ }
}
}
}
@@ -1520,7 +1580,7 @@
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
sp<InputWindowHandle> foregroundWindowHandle =
mTempTouchState.getFirstForegroundWindowHandle();
- if (foregroundWindowHandle->getInfo()->hasWallpaper) {
+ if (foregroundWindowHandle && foregroundWindowHandle->getInfo()->hasWallpaper) {
const std::vector<sp<InputWindowHandle>> windowHandles =
getWindowHandlesLocked(displayId);
for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
@@ -1546,6 +1606,11 @@
touchedWindow.pointerIds, inputTargets);
}
+ for (const TouchedMonitor& touchedMonitor : mTempTouchState.gestureMonitors) {
+ addMonitoringTargetLocked(touchedMonitor.monitor, touchedMonitor.xOffset,
+ touchedMonitor.yOffset, inputTargets);
+ }
+
// Drop the outside or hover touch windows since we will not care about them
// in the next iteration.
mTempTouchState.filterNonAsIsTouchWindows();
@@ -1675,31 +1740,32 @@
inputTargets.push_back(target);
}
-void InputDispatcher::addMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets,
- int32_t displayId, float xOffset, float yOffset) {
- std::unordered_map<int32_t, std::vector<sp<InputChannel>>>::const_iterator it =
- mMonitoringChannelsByDisplay.find(displayId);
+void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets,
+ int32_t displayId, float xOffset, float yOffset) {
- if (it != mMonitoringChannelsByDisplay.end()) {
- const std::vector<sp<InputChannel>>& monitoringChannels = it->second;
- const size_t numChannels = monitoringChannels.size();
- for (size_t i = 0; i < numChannels; i++) {
- InputTarget target;
- target.inputChannel = monitoringChannels[i];
- target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
- target.xOffset = xOffset;
- target.yOffset = yOffset;
- target.pointerIds.clear();
- target.globalScaleFactor = 1.0f;
- inputTargets.push_back(target);
+ std::unordered_map<int32_t, std::vector<Monitor>>::const_iterator it =
+ mGlobalMonitorsByDisplay.find(displayId);
+
+ if (it != mGlobalMonitorsByDisplay.end()) {
+ const std::vector<Monitor>& monitors = it->second;
+ for (const Monitor& monitor : monitors) {
+ addMonitoringTargetLocked(monitor, xOffset, yOffset, inputTargets);
}
- } else {
- // If there is no monitor channel registered or all monitor channel unregistered,
- // the display can't detect the extra system gesture by a copy of input events.
- ALOGW("There is no monitor channel found in display %" PRId32, displayId);
}
}
+void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor,
+ float xOffset, float yOffset, std::vector<InputTarget>& inputTargets) {
+ InputTarget target;
+ target.inputChannel = monitor.inputChannel;
+ target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+ target.xOffset = xOffset;
+ target.yOffset = yOffset;
+ target.pointerIds.clear();
+ target.globalScaleFactor = 1.0f;
+ inputTargets.push_back(target);
+}
+
bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
const InjectionState* injectionState) {
if (injectionState
@@ -1905,6 +1971,12 @@
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
+ if (ATRACE_ENABLED()) {
+ std::string message = StringPrintf(
+ "prepareDispatchCycleLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")",
+ connection->getInputChannelName().c_str(), eventEntry->sequenceNum);
+ ATRACE_NAME(message.c_str());
+ }
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
"xOffset=%f, yOffset=%f, globalScaleFactor=%f, "
@@ -1955,6 +2027,13 @@
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
+ if (ATRACE_ENABLED()) {
+ std::string message = StringPrintf(
+ "enqueueDispatchEntriesLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")",
+ connection->getInputChannelName().c_str(), eventEntry->sequenceNum);
+ ATRACE_NAME(message.c_str());
+ }
+
bool wasEmpty = connection->outboundQueue.isEmpty();
// Enqueue dispatch entries for the requested modes.
@@ -1980,6 +2059,13 @@
void InputDispatcher::enqueueDispatchEntryLocked(
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
int32_t dispatchMode) {
+ if (ATRACE_ENABLED()) {
+ std::string message = StringPrintf(
+ "enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)",
+ connection->getInputChannelName().c_str(),
+ dispatchModeToString(dispatchMode).c_str());
+ ATRACE_NAME(message.c_str());
+ }
int32_t inputTargetFlags = inputTarget->flags;
if (!(inputTargetFlags & dispatchMode)) {
return;
@@ -2100,6 +2186,11 @@
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
+ if (ATRACE_ENABLED()) {
+ std::string message = StringPrintf("startDispatchCycleLocked(inputChannel=%s)",
+ connection->getInputChannelName().c_str());
+ ATRACE_NAME(message.c_str());
+ }
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ startDispatchCycle",
connection->getInputChannelName().c_str());
@@ -2347,11 +2438,17 @@
void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked (
const CancelationOptions& options) {
- for (auto& it : mMonitoringChannelsByDisplay) {
- const std::vector<sp<InputChannel>>& monitoringChannels = it.second;
- const size_t numChannels = monitoringChannels.size();
- for (size_t i = 0; i < numChannels; i++) {
- synthesizeCancelationEventsForInputChannelLocked(monitoringChannels[i], options);
+ synthesizeCancelationEventsForMonitorsLocked(options, mGlobalMonitorsByDisplay);
+ synthesizeCancelationEventsForMonitorsLocked(options, mGestureMonitorsByDisplay);
+}
+
+void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked(
+ const CancelationOptions& options,
+ std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) {
+ for (const auto& it : monitorsByDisplay) {
+ const std::vector<Monitor>& monitors = it.second;
+ for (const Monitor& monitor : monitors) {
+ synthesizeCancelationEventsForInputChannelLocked(monitor.inputChannel, options);
}
}
}
@@ -3293,8 +3390,9 @@
getInputChannelLocked(oldFocusedWindowHandle->getToken());
if (inputChannel != nullptr) {
CancelationOptions options(
- CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS,
+ CancelationOptions::CANCEL_NON_POINTER_EVENTS,
"The display which contains this window no longer has focus.");
+ options.displayId = ADISPLAY_ID_NONE;
synthesizeCancelationEventsForInputChannelLocked(inputChannel, options);
}
}
@@ -3604,18 +3702,19 @@
dump += INDENT "Displays: <none>\n";
}
- if (!mMonitoringChannelsByDisplay.empty()) {
- for (auto& it : mMonitoringChannelsByDisplay) {
- const std::vector<sp<InputChannel>>& monitoringChannels = it.second;
- dump += StringPrintf(INDENT "MonitoringChannels in display %" PRId32 ":\n", it.first);
- const size_t numChannels = monitoringChannels.size();
- for (size_t i = 0; i < numChannels; i++) {
- const sp<InputChannel>& channel = monitoringChannels[i];
- dump += StringPrintf(INDENT2 "%zu: '%s'\n", i, channel->getName().c_str());
- }
+ if (!mGlobalMonitorsByDisplay.empty() || !mGestureMonitorsByDisplay.empty()) {
+ for (auto& it : mGlobalMonitorsByDisplay) {
+ const std::vector<Monitor>& monitors = it.second;
+ dump += StringPrintf(INDENT "Global monitors in display %" PRId32 ":\n", it.first);
+ dumpMonitors(dump, monitors);
+ }
+ for (auto& it : mGestureMonitorsByDisplay) {
+ const std::vector<Monitor>& monitors = it.second;
+ dump += StringPrintf(INDENT "Gesture monitors in display %" PRId32 ":\n", it.first);
+ dumpMonitors(dump, monitors);
}
} else {
- dump += INDENT "MonitoringChannels: <none>\n";
+ dump += INDENT "Monitors: <none>\n";
}
nsecs_t currentTime = now();
@@ -3730,7 +3829,18 @@
mConfig.keyRepeatTimeout * 0.000001f);
}
-status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, int32_t displayId) {
+void InputDispatcher::dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors) {
+ const size_t numMonitors = monitors.size();
+ for (size_t i = 0; i < numMonitors; i++) {
+ const Monitor& monitor = monitors[i];
+ const sp<InputChannel>& channel = monitor.inputChannel;
+ dump += StringPrintf(INDENT2 "%zu: '%s', ", i, channel->getName().c_str());
+ dump += "\n";
+ }
+}
+
+status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
+ int32_t displayId) {
#if DEBUG_REGISTRATION
ALOGD("channel '%s' ~ registerInputChannel - displayId=%" PRId32,
inputChannel->getName().c_str(), displayId);
@@ -3739,32 +3849,18 @@
{ // acquire lock
std::scoped_lock _l(mLock);
- // If InputWindowHandle is null and displayId is not ADISPLAY_ID_NONE,
- // treat inputChannel as monitor channel for displayId.
- bool monitor = inputChannel->getToken() == nullptr && displayId != ADISPLAY_ID_NONE;
- if (monitor) {
- inputChannel->setToken(new BBinder());
- }
-
if (getConnectionIndexLocked(inputChannel) >= 0) {
ALOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().c_str());
return BAD_VALUE;
}
- sp<Connection> connection = new Connection(inputChannel, monitor);
+ sp<Connection> connection = new Connection(inputChannel, false /*monitor*/);
int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection);
mInputChannelsByToken[inputChannel->getToken()] = inputChannel;
- // Store monitor channel by displayId.
- if (monitor) {
- std::vector<sp<InputChannel>>& monitoringChannels =
- mMonitoringChannelsByDisplay[displayId];
- monitoringChannels.push_back(inputChannel);
- }
-
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
@@ -3773,6 +3869,40 @@
return OK;
}
+status_t InputDispatcher::registerInputMonitor(const sp<InputChannel>& inputChannel,
+ int32_t displayId, bool isGestureMonitor) {
+ { // acquire lock
+ std::scoped_lock _l(mLock);
+
+ if (displayId < 0) {
+ ALOGW("Attempted to register input monitor without a specified display.");
+ return BAD_VALUE;
+ }
+
+ if (inputChannel->getToken() == nullptr) {
+ ALOGW("Attempted to register input monitor without an identifying token.");
+ return BAD_VALUE;
+ }
+
+ sp<Connection> connection = new Connection(inputChannel, true /*monitor*/);
+
+ const int fd = inputChannel->getFd();
+ mConnectionsByFd.add(fd, connection);
+ mInputChannelsByToken[inputChannel->getToken()] = inputChannel;
+
+ auto& monitorsByDisplay = isGestureMonitor
+ ? mGestureMonitorsByDisplay
+ : mGlobalMonitorsByDisplay;
+ monitorsByDisplay[displayId].emplace_back(inputChannel);
+
+ mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
+
+ }
+ // Wake the looper because some connections have changed.
+ mLooper->wake();
+ return OK;
+}
+
status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) {
#if DEBUG_REGISTRATION
ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().c_str());
@@ -3821,24 +3951,89 @@
}
void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) {
- for (auto it = mMonitoringChannelsByDisplay.begin();
- it != mMonitoringChannelsByDisplay.end(); ) {
- std::vector<sp<InputChannel>>& monitoringChannels = it->second;
- const size_t numChannels = monitoringChannels.size();
- for (size_t i = 0; i < numChannels; i++) {
- if (monitoringChannels[i] == inputChannel) {
- monitoringChannels.erase(monitoringChannels.begin() + i);
+ removeMonitorChannelLocked(inputChannel, mGlobalMonitorsByDisplay);
+ removeMonitorChannelLocked(inputChannel, mGestureMonitorsByDisplay);
+}
+
+void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel,
+ std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) {
+ for (auto it = monitorsByDisplay.begin(); it != monitorsByDisplay.end(); ) {
+ std::vector<Monitor>& monitors = it->second;
+ const size_t numMonitors = monitors.size();
+ for (size_t i = 0; i < numMonitors; i++) {
+ if (monitors[i].inputChannel == inputChannel) {
+ monitors.erase(monitors.begin() + i);
break;
}
}
- if (monitoringChannels.empty()) {
- it = mMonitoringChannelsByDisplay.erase(it);
+ if (monitors.empty()) {
+ it = monitorsByDisplay.erase(it);
} else {
++it;
}
}
}
+status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) {
+ { // acquire lock
+ std::scoped_lock _l(mLock);
+ std::optional<int32_t> foundDisplayId = findGestureMonitorDisplayByTokenLocked(token);
+
+ if (!foundDisplayId) {
+ ALOGW("Attempted to pilfer pointers from an un-registered monitor or invalid token");
+ return BAD_VALUE;
+ }
+ int32_t displayId = foundDisplayId.value();
+
+ ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId);
+ if (stateIndex < 0) {
+ ALOGW("Failed to pilfer pointers: no pointers on display %" PRId32 ".", displayId);
+ return BAD_VALUE;
+ }
+
+ TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex);
+ std::optional<int32_t> foundDeviceId;
+ for (const TouchedMonitor& touchedMonitor : state.gestureMonitors) {
+ if (touchedMonitor.monitor.inputChannel->getToken() == token) {
+ foundDeviceId = state.deviceId;
+ }
+ }
+ if (!foundDeviceId || !state.down) {
+ ALOGW("Attempted to pilfer points from a monitor without any on-going pointer streams."
+ " Ignoring.");
+ return BAD_VALUE;
+ }
+ int32_t deviceId = foundDeviceId.value();
+
+ // Send cancel events to all the input channels we're stealing from.
+ CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
+ "gesture monitor stole pointer stream");
+ options.deviceId = deviceId;
+ options.displayId = displayId;
+ for (const TouchedWindow& window : state.windows) {
+ sp<InputChannel> channel = getInputChannelLocked(window.windowHandle->getToken());
+ synthesizeCancelationEventsForInputChannelLocked(channel, options);
+ }
+ // Then clear the current touch state so we stop dispatching to them as well.
+ state.filterNonMonitors();
+ }
+ return OK;
+}
+
+
+std::optional<int32_t> InputDispatcher::findGestureMonitorDisplayByTokenLocked(
+ const sp<IBinder>& token) {
+ for (const auto& it : mGestureMonitorsByDisplay) {
+ const std::vector<Monitor>& monitors = it.second;
+ for (const Monitor& monitor : monitors) {
+ if (monitor.inputChannel->getToken() == token) {
+ return it.first;
+ }
+ }
+ }
+ return std::nullopt;
+}
+
ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
if (inputChannel == nullptr) {
return -1;
@@ -4807,11 +5002,15 @@
bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento,
const CancelationOptions& options) {
- if (options.keyCode != -1 && memento.keyCode != options.keyCode) {
+ if (options.keyCode && memento.keyCode != options.keyCode.value()) {
return false;
}
- if (options.deviceId != -1 && memento.deviceId != options.deviceId) {
+ if (options.deviceId && memento.deviceId != options.deviceId.value()) {
+ return false;
+ }
+
+ if (options.displayId && memento.displayId != options.displayId.value()) {
return false;
}
@@ -4821,8 +5020,6 @@
return true;
case CancelationOptions::CANCEL_FALLBACK_EVENTS:
return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
- case CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS:
- return memento.displayId == ADISPLAY_ID_NONE;
default:
return false;
}
@@ -4830,7 +5027,11 @@
bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento,
const CancelationOptions& options) {
- if (options.deviceId != -1 && memento.deviceId != options.deviceId) {
+ if (options.deviceId && memento.deviceId != options.deviceId.value()) {
+ return false;
+ }
+
+ if (options.displayId && memento.displayId != options.displayId.value()) {
return false;
}
@@ -4841,8 +5042,6 @@
return memento.source & AINPUT_SOURCE_CLASS_POINTER;
case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
- case CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS:
- return memento.displayId == ADISPLAY_ID_NONE;
default:
return false;
}
@@ -4895,9 +5094,14 @@
return nullptr;
}
+// --- InputDispatcher::Monitor
+InputDispatcher::Monitor::Monitor(const sp<InputChannel>& inputChannel) :
+ inputChannel(inputChannel) {
+}
+
// --- InputDispatcher::CommandEntry ---
-
+//
InputDispatcher::CommandEntry::CommandEntry(Command command) :
command(command), eventTime(0), keyEntry(nullptr), userActivityEventType(0),
seq(0), handled(false) {
@@ -4906,6 +5110,10 @@
InputDispatcher::CommandEntry::~CommandEntry() {
}
+// --- InputDispatcher::TouchedMonitor ---
+InputDispatcher::TouchedMonitor::TouchedMonitor(const Monitor& monitor, float xOffset,
+ float yOffset) : monitor(monitor), xOffset(xOffset), yOffset(yOffset) {
+}
// --- InputDispatcher::TouchState ---
@@ -4924,6 +5132,7 @@
displayId = ADISPLAY_ID_NONE;
windows.clear();
portalWindows.clear();
+ gestureMonitors.clear();
}
void InputDispatcher::TouchState::copyFrom(const TouchState& other) {
@@ -4934,6 +5143,7 @@
displayId = other.displayId;
windows = other.windows;
portalWindows = other.portalWindows;
+ gestureMonitors = other.gestureMonitors;
}
void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
@@ -4971,6 +5181,14 @@
portalWindows.push_back(windowHandle);
}
+void InputDispatcher::TouchState::addGestureMonitors(
+ const std::vector<TouchedMonitor>& newMonitors) {
+ const size_t newSize = gestureMonitors.size() + newMonitors.size();
+ gestureMonitors.reserve(newSize);
+ gestureMonitors.insert(std::end(gestureMonitors),
+ std::begin(newMonitors), std::end(newMonitors));
+}
+
void InputDispatcher::TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) {
for (size_t i = 0; i < windows.size(); i++) {
if (windows[i].windowHandle == windowHandle) {
@@ -5003,6 +5221,11 @@
}
}
+void InputDispatcher::TouchState::filterNonMonitors() {
+ windows.clear();
+ portalWindows.clear();
+}
+
sp<InputWindowHandle> InputDispatcher::TouchState::getFirstForegroundWindowHandle() const {
for (size_t i = 0; i < windows.size(); i++) {
const TouchedWindow& window = windows[i];
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 3735a0b..65d6d67 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -23,6 +23,8 @@
#include <input/InputTransport.h>
#include <input/InputWindow.h>
#include <input/ISetInputWindowsListener.h>
+#include <optional>
+#include <ui/Region.h>
#include <utils/threads.h>
#include <utils/Timers.h>
#include <utils/RefBase.h>
@@ -351,19 +353,35 @@
virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
/* Registers input channels that may be used as targets for input events.
- * If inputWindowHandle is null, and displayId is not ADISPLAY_ID_NONE,
- * the channel will receive a copy of all input events form the specific displayId.
*
* This method may be called on any thread (usually by the input manager).
*/
virtual status_t registerInputChannel(
const sp<InputChannel>& inputChannel, int32_t displayId) = 0;
+ /* Registers input channels to be used to monitor input events.
+ *
+ * Each monitor must target a specific display and will only receive input events sent to that
+ * display. If the monitor is a gesture monitor, it will only receive pointer events on the
+ * targeted display.
+ *
+ * This method may be called on any thread (usually by the input manager).
+ */
+ virtual status_t registerInputMonitor(
+ const sp<InputChannel>& inputChannel, int32_t displayId, bool gestureMonitor) = 0;
+
/* Unregister input channels that will no longer receive input events.
*
* This method may be called on any thread (usually by the input manager).
*/
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
+
+ /* Allows an input monitor steal the current pointer stream away from normal input windows.
+ *
+ * This method may be called on any thread (usually by the input manager).
+ */
+ virtual status_t pilferPointers(const sp<IBinder>& token) = 0;
+
};
/* Dispatches events to input targets. Some functions of the input dispatcher, such as
@@ -390,35 +408,39 @@
public:
explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);
- virtual void dump(std::string& dump);
- virtual void monitor();
+ virtual void dump(std::string& dump) override;
+ virtual void monitor() override;
- virtual void dispatchOnce();
+ virtual void dispatchOnce() override;
- virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
- virtual void notifyKey(const NotifyKeyArgs* args);
- virtual void notifyMotion(const NotifyMotionArgs* args);
- virtual void notifySwitch(const NotifySwitchArgs* args);
- virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
+ virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
+ virtual void notifyKey(const NotifyKeyArgs* args) override;
+ virtual void notifyMotion(const NotifyMotionArgs* args) override;
+ virtual void notifySwitch(const NotifySwitchArgs* args) override;
+ virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
virtual int32_t injectInputEvent(const InputEvent* event,
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
- uint32_t policyFlags);
+ uint32_t policyFlags) override;
virtual void setInputWindows(const std::vector<sp<InputWindowHandle> >& inputWindowHandles,
int32_t displayId,
- const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr);
+ const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) override;
virtual void setFocusedApplication(int32_t displayId,
- const sp<InputApplicationHandle>& inputApplicationHandle);
- virtual void setFocusedDisplay(int32_t displayId);
- virtual void setInputDispatchMode(bool enabled, bool frozen);
- virtual void setInputFilterEnabled(bool enabled);
+ const sp<InputApplicationHandle>& inputApplicationHandle) override;
+ virtual void setFocusedDisplay(int32_t displayId) override;
+ virtual void setInputDispatchMode(bool enabled, bool frozen) override;
+ virtual void setInputFilterEnabled(bool enabled) override;
- virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
+ virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken)
+ override;
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
- int32_t displayId);
- virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
+ int32_t displayId) override;
+ virtual status_t registerInputMonitor(const sp<InputChannel>& inputChannel,
+ int32_t displayId, bool isGestureMonitor) override;
+ virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) override;
+ virtual status_t pilferPointers(const sp<IBinder>& token) override;
private:
template <typename T>
@@ -712,10 +734,6 @@
CANCEL_POINTER_EVENTS = 1,
CANCEL_NON_POINTER_EVENTS = 2,
CANCEL_FALLBACK_EVENTS = 3,
-
- /* Cancel events where the display not specified. These events would go to the focused
- * display. */
- CANCEL_DISPLAY_UNSPECIFIED_EVENTS = 4,
};
// The criterion to use to determine which events should be canceled.
@@ -724,14 +742,16 @@
// Descriptive reason for the cancelation.
const char* reason;
- // The specific keycode of the key event to cancel, or -1 to cancel any key event.
- int32_t keyCode;
+ // The specific keycode of the key event to cancel, or nullopt to cancel any key event.
+ std::optional<int32_t> keyCode = std::nullopt;
- // The specific device id of events to cancel, or -1 to cancel events from any device.
- int32_t deviceId;
+ // The specific device id of events to cancel, or nullopt to cancel events from any device.
+ std::optional<int32_t> deviceId = std::nullopt;
- CancelationOptions(Mode mode, const char* reason) :
- mode(mode), reason(reason), keyCode(-1), deviceId(-1) { }
+ // The specific display id of events to cancel, or nullopt to cancel events on any display.
+ std::optional<int32_t> displayId = std::nullopt;
+
+ CancelationOptions(Mode mode, const char* reason) : mode(mode), reason(reason) { }
};
/* Tracks dispatched key and motion event state so that cancelation events can be
@@ -871,6 +891,12 @@
DispatchEntry* findWaitQueueEntry(uint32_t seq);
};
+ struct Monitor {
+ sp<InputChannel> inputChannel; // never null
+
+ explicit Monitor(const sp<InputChannel>& inputChannel);
+ };
+
enum DropReason {
DROP_REASON_NOT_DROPPED = 0,
DROP_REASON_POLICY = 1,
@@ -936,12 +962,24 @@
std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken
GUARDED_BY(mLock);
+ // Finds the display ID of the gesture monitor identified by the provided token.
+ std::optional<int32_t> findGestureMonitorDisplayByTokenLocked(const sp<IBinder>& token)
+ REQUIRES(mLock);
+
ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock);
// Input channels that will receive a copy of all input events sent to the provided display.
- std::unordered_map<int32_t, std::vector<sp<InputChannel>>> mMonitoringChannelsByDisplay
+ std::unordered_map<int32_t, std::vector<Monitor>> mGlobalMonitorsByDisplay
GUARDED_BY(mLock);
+ // Input channels that will receive pointer events that start within the corresponding display.
+ // These are a bit special when compared to global monitors since they'll cause gesture streams
+ // to continue even when there isn't a touched window,and have the ability to steal the rest of
+ // the pointer stream in order to claim it for a system gesture.
+ std::unordered_map<int32_t, std::vector<Monitor>> mGestureMonitorsByDisplay
+ GUARDED_BY(mLock);
+
+
// Event injection and synchronization.
std::condition_variable mInjectionResultAvailable;
bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
@@ -1016,6 +1054,16 @@
int32_t targetFlags;
BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set
};
+
+ // For tracking the offsets we need to apply when adding gesture monitor targets.
+ struct TouchedMonitor {
+ Monitor monitor;
+ float xOffset = 0.f;
+ float yOffset = 0.f;
+
+ explicit TouchedMonitor(const Monitor& monitor, float xOffset, float yOffset);
+ };
+
struct TouchState {
bool down;
bool split;
@@ -1029,6 +1077,8 @@
// monitoring channels of the displays touched.
std::vector<sp<InputWindowHandle>> portalWindows;
+ std::vector<TouchedMonitor> gestureMonitors;
+
TouchState();
~TouchState();
void reset();
@@ -1036,9 +1086,11 @@
void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds);
void addPortalWindow(const sp<InputWindowHandle>& windowHandle);
+ void addGestureMonitors(const std::vector<TouchedMonitor>& monitors);
void removeWindow(const sp<InputWindowHandle>& windowHandle);
void removeWindowByToken(const sp<IBinder>& token);
void filterNonAsIsTouchWindows();
+ void filterNonMonitors();
sp<InputWindowHandle> getFirstForegroundWindowHandle() const;
bool isSlippery() const;
};
@@ -1108,12 +1160,18 @@
int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
bool* outConflictingPointerActions) REQUIRES(mLock);
+ std::vector<TouchedMonitor> findTouchedGestureMonitorsLocked(int32_t displayId,
+ const std::vector<sp<InputWindowHandle>>& portalWindows) REQUIRES(mLock);
+ void addGestureMonitors(const std::vector<Monitor>& monitors,
+ std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset = 0, float yOffset = 0);
void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds, std::vector<InputTarget>& inputTargets)
REQUIRES(mLock);
- void addMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId,
- float xOffset = 0, float yOffset = 0) REQUIRES(mLock);
+ void addMonitoringTargetLocked(const Monitor& monitor, float xOffset, float yOffset,
+ std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
+ void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets,
+ int32_t displayId, float xOffset = 0, float yOffset = 0) REQUIRES(mLock);
void pokeUserActivityLocked(const EventEntry* eventEntry) REQUIRES(mLock);
bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
@@ -1156,6 +1214,8 @@
const CancelationOptions& options) REQUIRES(mLock);
void synthesizeCancelationEventsForMonitorsLocked(
const CancelationOptions& options) REQUIRES(mLock);
+ void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options,
+ std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock);
void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
const CancelationOptions& options) REQUIRES(mLock);
void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
@@ -1169,10 +1229,14 @@
// Dump state.
void dumpDispatchStateLocked(std::string& dump) REQUIRES(mLock);
+ void dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors);
void logDispatchStateLocked() REQUIRES(mLock);
// Registration.
void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock);
+ void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel,
+ std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay)
+ REQUIRES(mLock);
status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify)
REQUIRES(mLock);
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 745fac0..38a8c6f 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -416,7 +416,6 @@
sp<InputDispatcher> mDispatcher;
sp<InputChannel> mServerChannel, mClientChannel;
- sp<IBinder> mToken;
InputConsumer *mConsumer;
PreallocatedInputEventFactory mEventFactory;
@@ -435,7 +434,7 @@
mFocused(false) {
mServerChannel->setToken(new BBinder());
mDispatcher->registerInputChannel(mServerChannel, displayId);
-
+
inputApplicationHandle->updateInfo();
mInfo.applicationInfo = *inputApplicationHandle->getInfo();
}
@@ -776,8 +775,10 @@
class FakeMonitorReceiver : public FakeInputReceiver, public RefBase {
public:
FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,
- int32_t displayId) : FakeInputReceiver(dispatcher, name, displayId) {
- mDispatcher->registerInputChannel(mServerChannel, displayId);
+ int32_t displayId, bool isGestureMonitor = false)
+ : FakeInputReceiver(dispatcher, name, displayId) {
+ mServerChannel->setToken(new BBinder());
+ mDispatcher->registerInputMonitor(mServerChannel, displayId, isGestureMonitor);
}
};