summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--services/input/InputReader.cpp197
-rw-r--r--services/input/InputReader.h28
-rw-r--r--services/input/PointerController.h3
3 files changed, 161 insertions, 67 deletions
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 1bc1bd1..98b3526 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -72,9 +72,14 @@ static const float DRAG_MIN_SWITCH_SPEED = 50.0f; // pixels per second
// The time between down and up must be less than this to be considered a tap.
static const nsecs_t TAP_INTERVAL = 150 * 1000000; // 150 ms
+// Tap drag gesture delay time.
+// The time between up and the next up must be greater than this to be considered a
+// drag. Otherwise, the previous tap is finished and a new tap begins.
+static const nsecs_t TAP_DRAG_INTERVAL = 150 * 1000000; // 150 ms
+
// The distance in pixels that the pointer is allowed to move from initial down
// to up and still be called a tap.
-static const float TAP_SLOP = 5.0f; // 5 pixels
+static const float TAP_SLOP = 10.0f; // 10 pixels
// Time after the first touch points go down to settle on an initial centroid.
// This is intended to be enough time to handle cases where the user puts down two
@@ -2761,14 +2766,21 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
}
}
- // Process touches and virtual keys.
- TouchResult touchResult = consumeOffScreenTouches(when, policyFlags);
- if (touchResult == DISPATCH_TOUCH) {
- suppressSwipeOntoVirtualKeys(when);
- if (mPointerController != NULL) {
- dispatchPointerGestures(when, policyFlags);
+ TouchResult touchResult;
+ if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount == 0
+ && mLastTouch.buttonState == mCurrentTouch.buttonState) {
+ // Drop spurious syncs.
+ touchResult = DROP_STROKE;
+ } else {
+ // Process touches and virtual keys.
+ touchResult = consumeOffScreenTouches(when, policyFlags);
+ if (touchResult == DISPATCH_TOUCH) {
+ suppressSwipeOntoVirtualKeys(when);
+ if (mPointerController != NULL) {
+ dispatchPointerGestures(when, policyFlags, false /*isTimeout*/);
+ }
+ dispatchTouches(when, policyFlags);
}
- dispatchTouches(when, policyFlags);
}
// Copy current touch to last touch in preparation for the next cycle.
@@ -2781,6 +2793,12 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
}
}
+void TouchInputMapper::timeoutExpired(nsecs_t when) {
+ if (mPointerController != NULL) {
+ dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/);
+ }
+}
+
TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches(
nsecs_t when, uint32_t policyFlags) {
int32_t keyEventAction, keyEventFlags;
@@ -3224,7 +3242,8 @@ void TouchInputMapper::prepareTouches(int32_t* outEdgeFlags,
*outYPrecision = mLocked.orientedYPrecision;
}
-void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags) {
+void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags,
+ bool isTimeout) {
// Switch pointer presentation.
mPointerController->setPresentation(
mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS
@@ -3233,7 +3252,11 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
// Update current gesture coordinates.
bool cancelPreviousGesture, finishPreviousGesture;
- preparePointerGestures(when, &cancelPreviousGesture, &finishPreviousGesture);
+ bool sendEvents = preparePointerGestures(when,
+ &cancelPreviousGesture, &finishPreviousGesture, isTimeout);
+ if (!sendEvents) {
+ return;
+ }
// Show the pointer if needed.
if (mPointerGesture.currentGestureMode != PointerGesture::NEUTRAL
@@ -3246,7 +3269,9 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
// Update last coordinates of pointers that have moved so that we observe the new
// pointer positions at the same time as other pointers that have just gone up.
- bool down = mPointerGesture.currentGestureMode == PointerGesture::CLICK_OR_DRAG
+ bool down = mPointerGesture.currentGestureMode == PointerGesture::TAP
+ || mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG
+ || mPointerGesture.currentGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG
|| mPointerGesture.currentGestureMode == PointerGesture::PRESS
|| mPointerGesture.currentGestureMode == PointerGesture::SWIPE
|| mPointerGesture.currentGestureMode == PointerGesture::FREEFORM;
@@ -3334,27 +3359,6 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
}
}
- // Send down and up for a tap.
- if (mPointerGesture.currentGestureMode == PointerGesture::TAP) {
- const PointerCoords& coords = mPointerGesture.currentGestureCoords[0];
- int32_t edgeFlags = calculateEdgeFlagsUsingPointerBounds(mPointerController,
- coords.getAxisValue(AMOTION_EVENT_AXIS_X),
- coords.getAxisValue(AMOTION_EVENT_AXIS_Y));
- nsecs_t downTime = mPointerGesture.downTime = mPointerGesture.tapTime;
- mPointerGesture.resetTapTime();
-
- dispatchMotion(downTime, policyFlags, mPointerSource,
- AMOTION_EVENT_ACTION_DOWN, 0, metaState, edgeFlags,
- mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
- mPointerGesture.currentGestureIdBits, -1,
- 0, 0, downTime);
- dispatchMotion(when, policyFlags, mPointerSource,
- AMOTION_EVENT_ACTION_UP, 0, metaState, edgeFlags,
- mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
- mPointerGesture.currentGestureIdBits, -1,
- 0, 0, downTime);
- }
-
// Send motion events for hover.
if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) {
dispatchMotion(when, policyFlags, mPointerSource,
@@ -3381,13 +3385,49 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
}
}
-void TouchInputMapper::preparePointerGestures(nsecs_t when,
- bool* outCancelPreviousGesture, bool* outFinishPreviousGesture) {
+bool TouchInputMapper::preparePointerGestures(nsecs_t when,
+ bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout) {
*outCancelPreviousGesture = false;
*outFinishPreviousGesture = false;
AutoMutex _l(mLock);
+ // Handle TAP timeout.
+ if (isTimeout) {
+#if DEBUG_GESTURES
+ LOGD("Gestures: Processing timeout");
+#endif
+
+ if (mPointerGesture.lastGestureMode == PointerGesture::TAP) {
+ if (when <= mPointerGesture.tapUpTime + TAP_DRAG_INTERVAL) {
+ // The tap/drag timeout has not yet expired.
+ getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime + TAP_DRAG_INTERVAL);
+ } else {
+ // The tap is finished.
+#if DEBUG_GESTURES
+ LOGD("Gestures: TAP finished");
+#endif
+ *outFinishPreviousGesture = true;
+
+ mPointerGesture.activeGestureId = -1;
+ mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
+ mPointerGesture.currentGestureIdBits.clear();
+
+ mPointerController->setButtonState(0);
+
+ if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
+ mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL;
+ mPointerGesture.spotIdBits.clear();
+ moveSpotsLocked();
+ }
+ return true;
+ }
+ }
+
+ // We did not handle this timeout.
+ return false;
+ }
+
// Update the velocity tracker.
{
VelocityTracker::Position positions[MAX_POINTERS];
@@ -3442,7 +3482,7 @@ void TouchInputMapper::preparePointerGestures(nsecs_t when,
// This is to prevent accidentally entering the hover state and flinging the
// pointer when finishing a swipe and there is still one pointer left onscreen.
isQuietTime = true;
- } else if (mPointerGesture.lastGestureMode == PointerGesture::CLICK_OR_DRAG
+ } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG
&& mCurrentTouch.pointerCount >= 2
&& !isPointerDown(mCurrentTouch.buttonState)) {
// Enter quiet time when releasing the button and there are still two or more
@@ -3477,7 +3517,7 @@ void TouchInputMapper::preparePointerGestures(nsecs_t when,
moveSpotsLocked();
}
} else if (isPointerDown(mCurrentTouch.buttonState)) {
- // Case 2: Button is pressed. (CLICK_OR_DRAG)
+ // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG)
// The pointer follows the active touch point.
// Emit DOWN, MOVE, UP events at the pointer location.
//
@@ -3491,11 +3531,11 @@ void TouchInputMapper::preparePointerGestures(nsecs_t when,
// finger to drag then the active pointer should switch to the finger that is
// being dragged.
#if DEBUG_GESTURES
- LOGD("Gestures: CLICK_OR_DRAG activeTouchId=%d, "
+ LOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, "
"currentTouchPointerCount=%d", activeTouchId, mCurrentTouch.pointerCount);
#endif
// Reset state when just starting.
- if (mPointerGesture.lastGestureMode != PointerGesture::CLICK_OR_DRAG) {
+ if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) {
*outFinishPreviousGesture = true;
mPointerGesture.activeGestureId = 0;
}
@@ -3521,7 +3561,7 @@ void TouchInputMapper::preparePointerGestures(nsecs_t when,
mPointerGesture.activeTouchId = activeTouchId = bestId;
activeTouchChanged = true;
#if DEBUG_GESTURES
- LOGD("Gestures: CLICK_OR_DRAG switched pointers, "
+ LOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, "
"bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed);
#endif
}
@@ -3547,7 +3587,7 @@ void TouchInputMapper::preparePointerGestures(nsecs_t when,
float x, y;
mPointerController->getPosition(&x, &y);
- mPointerGesture.currentGestureMode = PointerGesture::CLICK_OR_DRAG;
+ mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG;
mPointerGesture.currentGestureIdBits.clear();
mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
@@ -3584,11 +3624,12 @@ void TouchInputMapper::preparePointerGestures(nsecs_t when,
// Case 3. No fingers down and button is not pressed. (NEUTRAL)
*outFinishPreviousGesture = true;
- // Watch for taps coming out of HOVER mode.
+ // Watch for taps coming out of HOVER or TAP_DRAG mode.
bool tapped = false;
- if (mPointerGesture.lastGestureMode == PointerGesture::HOVER
+ if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER
+ || mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG)
&& mLastTouch.pointerCount == 1) {
- if (when <= mPointerGesture.tapTime + TAP_INTERVAL) {
+ if (when <= mPointerGesture.tapDownTime + TAP_INTERVAL) {
float x, y;
mPointerController->getPosition(&x, &y);
if (fabs(x - mPointerGesture.tapX) <= TAP_SLOP
@@ -3596,6 +3637,10 @@ void TouchInputMapper::preparePointerGestures(nsecs_t when,
#if DEBUG_GESTURES
LOGD("Gestures: TAP");
#endif
+
+ mPointerGesture.tapUpTime = when;
+ getContext()->requestTimeoutAtTime(when + TAP_DRAG_INTERVAL);
+
mPointerGesture.activeGestureId = 0;
mPointerGesture.currentGestureMode = PointerGesture::TAP;
mPointerGesture.currentGestureIdBits.clear();
@@ -3612,7 +3657,6 @@ void TouchInputMapper::preparePointerGestures(nsecs_t when,
AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
mPointerController->setButtonState(BUTTON_STATE_PRIMARY);
- mPointerController->setButtonState(0);
if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_TAP;
@@ -3633,8 +3677,8 @@ void TouchInputMapper::preparePointerGestures(nsecs_t when,
}
} else {
#if DEBUG_GESTURES
- LOGD("Gestures: Not a TAP, delay=%lld",
- when - mPointerGesture.tapTime);
+ LOGD("Gestures: Not a TAP, %0.3fms since down",
+ (when - mPointerGesture.tapDownTime) * 0.000001f);
#endif
}
}
@@ -3656,14 +3700,36 @@ void TouchInputMapper::preparePointerGestures(nsecs_t when,
}
}
} else if (mCurrentTouch.pointerCount == 1) {
- // Case 4. Exactly one finger down, button is not pressed. (HOVER)
+ // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG)
// The pointer follows the active touch point.
- // Emit HOVER_MOVE events at the pointer location.
+ // When in HOVER, emit HOVER_MOVE events at the pointer location.
+ // When in TAP_DRAG, emit MOVE events at the pointer location.
LOG_ASSERT(activeTouchId >= 0);
+ mPointerGesture.currentGestureMode = PointerGesture::HOVER;
+ if (mPointerGesture.lastGestureMode == PointerGesture::TAP) {
+ if (when <= mPointerGesture.tapUpTime + TAP_DRAG_INTERVAL) {
+ float x, y;
+ mPointerController->getPosition(&x, &y);
+ if (fabs(x - mPointerGesture.tapX) <= TAP_SLOP
+ && fabs(y - mPointerGesture.tapY) <= TAP_SLOP) {
+ mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
+ } else {
+#if DEBUG_GESTURES
+ LOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f",
+ x - mPointerGesture.tapX,
+ y - mPointerGesture.tapY);
+#endif
+ }
+ } else {
#if DEBUG_GESTURES
- LOGD("Gestures: HOVER");
+ LOGD("Gestures: Not a TAP_DRAG, %0.3fms time since up",
+ (when - mPointerGesture.tapUpTime) * 0.000001f);
#endif
+ }
+ } else if (mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) {
+ mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
+ }
if (mLastTouch.idBits.hasBit(activeTouchId)) {
const PointerData& currentPointer =
@@ -3676,35 +3742,49 @@ void TouchInputMapper::preparePointerGestures(nsecs_t when,
* mLocked.pointerGestureYMovementScale;
// Move the pointer using a relative motion.
- // When using spots, the hover will occur at the position of the anchor spot.
+ // When using spots, the hover or drag will occur at the position of the anchor spot.
mPointerController->move(deltaX, deltaY);
}
- *outFinishPreviousGesture = true;
- mPointerGesture.activeGestureId = 0;
+ bool down;
+ if (mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG) {
+#if DEBUG_GESTURES
+ LOGD("Gestures: TAP_DRAG");
+#endif
+ down = true;
+ } else {
+#if DEBUG_GESTURES
+ LOGD("Gestures: HOVER");
+#endif
+ *outFinishPreviousGesture = true;
+ mPointerGesture.activeGestureId = 0;
+ down = false;
+ }
float x, y;
mPointerController->getPosition(&x, &y);
- mPointerGesture.currentGestureMode = PointerGesture::HOVER;
mPointerGesture.currentGestureIdBits.clear();
mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
mPointerGesture.currentGestureCoords[0].clear();
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
- mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.0f);
+ mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
+ down ? 1.0f : 0.0f);
+
+ mPointerController->setButtonState(down ? BUTTON_STATE_PRIMARY : 0);
if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) {
- mPointerGesture.tapTime = when;
+ mPointerGesture.resetTap();
+ mPointerGesture.tapDownTime = when;
mPointerGesture.tapX = x;
mPointerGesture.tapY = y;
}
- mPointerController->setButtonState(0);
-
if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
- mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_HOVER;
+ mPointerGesture.spotGesture = down ? PointerControllerInterface::SPOT_GESTURE_DRAG
+ : PointerControllerInterface::SPOT_GESTURE_HOVER;
mPointerGesture.spotIdBits.clear();
mPointerGesture.spotIdBits.markBit(activeTouchId);
mPointerGesture.spotIdToIndex[activeTouchId] = 0;
@@ -4107,6 +4187,7 @@ void TouchInputMapper::preparePointerGestures(nsecs_t when,
coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
}
#endif
+ return true;
}
void TouchInputMapper::moveSpotsLocked() {
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 9b2f4d2..0485617 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -570,6 +570,7 @@ public:
const int32_t* keyCodes, uint8_t* outFlags);
virtual void fadePointer();
+ virtual void timeoutExpired(nsecs_t when);
protected:
Mutex mLock;
@@ -935,10 +936,15 @@ private:
// Emits DOWN and UP events at the pointer location.
TAP,
+ // Exactly one finger dragging following a tap.
+ // Pointer follows the active finger.
+ // Emits DOWN, MOVE and UP events at the pointer location.
+ TAP_DRAG,
+
// Button is pressed.
// Pointer follows the active finger if there is one. Other fingers are ignored.
// Emits DOWN, MOVE and UP events at the pointer location.
- CLICK_OR_DRAG,
+ BUTTON_CLICK_OR_DRAG,
// Exactly one finger, button is not pressed.
// Pointer follows the active finger.
@@ -997,8 +1003,11 @@ private:
// Time the pointer gesture last went down.
nsecs_t downTime;
- // Time we started waiting for a tap gesture.
- nsecs_t tapTime;
+ // Time when the pointer went down for a TAP.
+ nsecs_t tapDownTime;
+
+ // Time when the pointer went up for a TAP.
+ nsecs_t tapUpTime;
// Location of initial tap.
float tapX, tapY;
@@ -1030,12 +1039,13 @@ private:
spotIdBits.clear();
downTime = 0;
velocityTracker.clear();
- resetTapTime();
+ resetTap();
resetQuietTime();
}
- void resetTapTime() {
- tapTime = LLONG_MIN;
+ void resetTap() {
+ tapDownTime = LLONG_MIN;
+ tapUpTime = LLONG_MIN;
}
void resetQuietTime() {
@@ -1048,9 +1058,9 @@ private:
TouchResult consumeOffScreenTouches(nsecs_t when, uint32_t policyFlags);
void dispatchTouches(nsecs_t when, uint32_t policyFlags);
void prepareTouches(int32_t* outEdgeFlags, float* outXPrecision, float* outYPrecision);
- void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags);
- void preparePointerGestures(nsecs_t when,
- bool* outCancelPreviousGesture, bool* outFinishPreviousGesture);
+ void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout);
+ bool preparePointerGestures(nsecs_t when,
+ bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout);
void moveSpotsLocked();
// Dispatches a motion event.
diff --git a/services/input/PointerController.h b/services/input/PointerController.h
index afd6371..b9184ac 100644
--- a/services/input/PointerController.h
+++ b/services/input/PointerController.h
@@ -91,6 +91,9 @@ public:
// Tap at current location.
// Briefly display one spot at the tapped location.
SPOT_GESTURE_TAP,
+ // Drag at current location.
+ // Display spot at pressed location.
+ SPOT_GESTURE_DRAG,
// Button pressed but no finger is down.
// Display spot at pressed location.
SPOT_GESTURE_BUTTON_CLICK,