summaryrefslogtreecommitdiffstats
path: root/services/input/InputDispatcher.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/input/InputDispatcher.cpp')
-rw-r--r--services/input/InputDispatcher.cpp165
1 files changed, 70 insertions, 95 deletions
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index ae11fb1..ef984d4 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -115,6 +115,7 @@ static bool isValidMotionAction(int32_t action, size_t pointerCount) {
case AMOTION_EVENT_ACTION_CANCEL:
case AMOTION_EVENT_ACTION_MOVE:
case AMOTION_EVENT_ACTION_OUTSIDE:
+ case AMOTION_EVENT_ACTION_HOVER_MOVE:
return true;
case AMOTION_EVENT_ACTION_POINTER_DOWN:
case AMOTION_EVENT_ACTION_POINTER_UP: {
@@ -318,7 +319,8 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout,
uint32_t source = motionEntry->source;
if (! isAppSwitchDue
&& motionEntry->next == & mInboundQueue.tailSentinel // exactly one event
- && motionEntry->action == AMOTION_EVENT_ACTION_MOVE
+ && (motionEntry->action == AMOTION_EVENT_ACTION_MOVE
+ || motionEntry->action == AMOTION_EVENT_ACTION_HOVER_MOVE)
&& deviceId == mThrottleState.lastDeviceId
&& source == mThrottleState.lastSource) {
nsecs_t nextTime = mThrottleState.lastEventTime
@@ -478,7 +480,8 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
// If the application takes too long to catch up then we drop all events preceding
// the touch into the other window.
MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
- if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
+ if ((motionEntry->action == AMOTION_EVENT_ACTION_DOWN
+ || motionEntry->action == AMOTION_EVENT_ACTION_HOVER_MOVE)
&& (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
&& mInputTargetWaitApplication != NULL) {
@@ -838,12 +841,13 @@ bool InputDispatcher::dispatchMotionLocked(
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
// Identify targets.
+ bool conflictingPointerActions = false;
if (! mCurrentInputTargetsValid) {
int32_t injectionResult;
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
injectionResult = findTouchedWindowTargetsLocked(currentTime,
- entry, nextWakeupTime);
+ entry, nextWakeupTime, &conflictingPointerActions);
} else {
// Non touch event. (eg. trackball)
injectionResult = findFocusedWindowTargetsLocked(currentTime,
@@ -863,6 +867,10 @@ bool InputDispatcher::dispatchMotionLocked(
}
// Dispatch the motion.
+ if (conflictingPointerActions) {
+ synthesizeCancelationEventsForAllConnectionsLocked(
+ InputState::CANCEL_POINTER_EVENTS, "Conflicting pointer actions.");
+ }
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
return true;
}
@@ -1123,7 +1131,7 @@ Unresponsive:
}
int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
- const MotionEntry* entry, nsecs_t* nextWakeupTime) {
+ const MotionEntry* entry, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) {
enum InjectionPermission {
INJECTION_PERMISSION_UNKNOWN,
INJECTION_PERMISSION_GRANTED,
@@ -1166,31 +1174,38 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
// Update the touch state as needed based on the properties of the touch event.
int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING;
InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
- bool isSplit, wrongDevice;
- if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
- mTempTouchState.reset();
- mTempTouchState.down = true;
- mTempTouchState.deviceId = entry->deviceId;
- mTempTouchState.source = entry->source;
- isSplit = false;
- wrongDevice = false;
+
+ bool isSplit = mTouchState.split;
+ bool wrongDevice = mTouchState.down
+ && (mTouchState.deviceId != entry->deviceId
+ || mTouchState.source != entry->source);
+ if (maskedAction == AMOTION_EVENT_ACTION_DOWN
+ || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
+ bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
+ if (wrongDevice && !down) {
+ mTempTouchState.copyFrom(mTouchState);
+ } else {
+ mTempTouchState.reset();
+ mTempTouchState.down = down;
+ mTempTouchState.deviceId = entry->deviceId;
+ mTempTouchState.source = entry->source;
+ isSplit = false;
+ wrongDevice = false;
+ }
} else {
mTempTouchState.copyFrom(mTouchState);
- isSplit = mTempTouchState.split;
- wrongDevice = mTempTouchState.down
- && (mTempTouchState.deviceId != entry->deviceId
- || mTempTouchState.source != entry->source);
- if (wrongDevice) {
+ }
+ if (wrongDevice) {
#if DEBUG_INPUT_DISPATCHER_POLICY
- LOGD("Dropping event because a pointer for a different device is already down.");
+ LOGD("Dropping event because a pointer for a different device is already down.");
#endif
- injectionResult = INPUT_EVENT_INJECTION_FAILED;
- goto Failed;
- }
+ injectionResult = INPUT_EVENT_INJECTION_FAILED;
+ goto Failed;
}
if (maskedAction == AMOTION_EVENT_ACTION_DOWN
- || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
+ || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)
+ || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
/* Case 1: New splittable pointer going down. */
int32_t pointerIndex = getMotionEventActionPointerIndex(action);
@@ -1365,7 +1380,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
// If this is the first pointer going down and the touched window has a wallpaper
// then also add the touched wallpaper windows so they are locked in for the duration
// of the touch gesture.
- if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
+ if (maskedAction == AMOTION_EVENT_ACTION_DOWN
+ || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
const InputWindow* foregroundWindow = mTempTouchState.getFirstForegroundWindow();
if (foregroundWindow->hasWallpaper) {
for (size_t i = 0; i < mWindows.size(); i++) {
@@ -1404,12 +1420,14 @@ Failed:
if (injectionPermission == INJECTION_PERMISSION_GRANTED) {
if (!wrongDevice) {
if (maskedAction == AMOTION_EVENT_ACTION_UP
- || maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
+ || maskedAction == AMOTION_EVENT_ACTION_CANCEL
+ || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
// All pointers up or canceled.
mTempTouchState.reset();
} else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
// First pointer went down.
if (mTouchState.down) {
+ *outConflictingPointerActions = true;
#if DEBUG_FOCUS
LOGD("Pointer down received while already down.");
#endif
@@ -1750,29 +1768,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
// Update the connection's input state.
EventEntry* eventEntry = dispatchEntry->eventEntry;
- InputState::Consistency consistency = connection->inputState.trackEvent(eventEntry);
-
-#if FILTER_INPUT_EVENTS
- // Filter out inconsistent sequences of input events.
- // The input system may drop or inject events in a way that could violate implicit
- // invariants on input state and potentially cause an application to crash
- // or think that a key or pointer is stuck down. Technically we make no guarantees
- // of consistency but it would be nice to improve on this where possible.
- // XXX: This code is a proof of concept only. Not ready for prime time.
- if (consistency == InputState::TOLERABLE) {
-#if DEBUG_DISPATCH_CYCLE
- LOGD("channel '%s' ~ Sending an event that is inconsistent with the connection's "
- "current input state but that is likely to be tolerated by the application.",
- connection->getInputChannelName());
-#endif
- } else if (consistency == InputState::BROKEN) {
- LOGI("channel '%s' ~ Dropping an event that is inconsistent with the connection's "
- "current input state and that is likely to cause the application to crash.",
- connection->getInputChannelName());
- startNextDispatchCycleLocked(currentTime, connection);
- return;
- }
-#endif
+ connection->inputState.trackEvent(eventEntry);
// Publish the event.
status_t status;
@@ -2307,7 +2303,8 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t
AutoMutex _l(mLock);
// Attempt batching and streaming of move events.
- if (action == AMOTION_EVENT_ACTION_MOVE) {
+ if (action == AMOTION_EVENT_ACTION_MOVE
+ || action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
// BATCHING CASE
//
// Try to append a move sample to the tail of the inbound queue for this device.
@@ -2326,7 +2323,7 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t
continue;
}
- if (motionEntry->action != AMOTION_EVENT_ACTION_MOVE
+ if (motionEntry->action != action
|| motionEntry->source != source
|| motionEntry->pointerCount != pointerCount
|| motionEntry->isInjected()) {
@@ -2385,7 +2382,7 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t
MotionEntry* motionEntry = static_cast<MotionEntry*>(
dispatchEntry->eventEntry);
- if (motionEntry->action != AMOTION_EVENT_ACTION_MOVE
+ if (motionEntry->action != action
|| motionEntry->deviceId != deviceId
|| motionEntry->source != source
|| motionEntry->pointerCount != pointerCount
@@ -3529,21 +3526,20 @@ bool InputDispatcher::InputState::isNeutral() const {
return mKeyMementos.isEmpty() && mMotionMementos.isEmpty();
}
-InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackEvent(
+void InputDispatcher::InputState::trackEvent(
const EventEntry* entry) {
switch (entry->type) {
case EventEntry::TYPE_KEY:
- return trackKey(static_cast<const KeyEntry*>(entry));
+ trackKey(static_cast<const KeyEntry*>(entry));
+ break;
case EventEntry::TYPE_MOTION:
- return trackMotion(static_cast<const MotionEntry*>(entry));
-
- default:
- return CONSISTENT;
+ trackMotion(static_cast<const MotionEntry*>(entry));
+ break;
}
}
-InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackKey(
+void InputDispatcher::InputState::trackKey(
const KeyEntry* entry) {
int32_t action = entry->action;
for (size_t i = 0; i < mKeyMementos.size(); i++) {
@@ -3555,19 +3551,20 @@ InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackKey(
switch (action) {
case AKEY_EVENT_ACTION_UP:
mKeyMementos.removeAt(i);
- return CONSISTENT;
+ return;
case AKEY_EVENT_ACTION_DOWN:
- return TOLERABLE;
+ mKeyMementos.removeAt(i);
+ goto Found;
default:
- return BROKEN;
+ return;
}
}
}
- switch (action) {
- case AKEY_EVENT_ACTION_DOWN: {
+Found:
+ if (action == AKEY_EVENT_ACTION_DOWN) {
mKeyMementos.push();
KeyMemento& memento = mKeyMementos.editTop();
memento.deviceId = entry->deviceId;
@@ -3576,15 +3573,10 @@ InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackKey(
memento.scanCode = entry->scanCode;
memento.flags = entry->flags;
memento.downTime = entry->downTime;
- return CONSISTENT;
- }
-
- default:
- return BROKEN;
}
}
-InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackMotion(
+void InputDispatcher::InputState::trackMotion(
const MotionEntry* entry) {
int32_t action = entry->action & AMOTION_EVENT_ACTION_MASK;
for (size_t i = 0; i < mMotionMementos.size(); i++) {
@@ -3594,40 +3586,28 @@ InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackMotio
switch (action) {
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_CANCEL:
+ case AMOTION_EVENT_ACTION_HOVER_MOVE:
mMotionMementos.removeAt(i);
- return CONSISTENT;
+ return;
case AMOTION_EVENT_ACTION_DOWN:
- return TOLERABLE;
-
- case AMOTION_EVENT_ACTION_POINTER_DOWN:
- if (entry->pointerCount == memento.pointerCount + 1) {
- memento.setPointers(entry);
- return CONSISTENT;
- }
- return BROKEN;
+ mMotionMementos.removeAt(i);
+ goto Found;
case AMOTION_EVENT_ACTION_POINTER_UP:
- if (entry->pointerCount == memento.pointerCount - 1) {
- memento.setPointers(entry);
- return CONSISTENT;
- }
- return BROKEN;
-
+ case AMOTION_EVENT_ACTION_POINTER_DOWN:
case AMOTION_EVENT_ACTION_MOVE:
- if (entry->pointerCount == memento.pointerCount) {
- return CONSISTENT;
- }
- return BROKEN;
+ memento.setPointers(entry);
+ return;
default:
- return BROKEN;
+ return;
}
}
}
- switch (action) {
- case AMOTION_EVENT_ACTION_DOWN: {
+Found:
+ if (action == AMOTION_EVENT_ACTION_DOWN) {
mMotionMementos.push();
MotionMemento& memento = mMotionMementos.editTop();
memento.deviceId = entry->deviceId;
@@ -3636,11 +3616,6 @@ InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackMotio
memento.yPrecision = entry->yPrecision;
memento.downTime = entry->downTime;
memento.setPointers(entry);
- return CONSISTENT;
- }
-
- default:
- return BROKEN;
}
}