Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 23e620b3 authored by Jeff Brown's avatar Jeff Brown Committed by Android Git Automerger
Browse files

am 53c3d5b1: am 325bd07b: Add tap/drag touchpad gesture. (DO NOT MERGE)

* commit '53c3d5b1':
  Add tap/drag touchpad gesture. (DO NOT MERGE)
parents 3c2fb024 53c3d5b1
Loading
Loading
Loading
Loading
+140 −59
Original line number Diff line number Diff line
@@ -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
@@ -2752,15 +2757,22 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
        }
    }

    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 touchResult = consumeOffScreenTouches(when, policyFlags);
        touchResult = consumeOffScreenTouches(when, policyFlags);
        if (touchResult == DISPATCH_TOUCH) {
            suppressSwipeOntoVirtualKeys(when);
            if (mPointerController != NULL) {
            dispatchPointerGestures(when, policyFlags);
                dispatchPointerGestures(when, policyFlags, false /*isTimeout*/);
            }
            dispatchTouches(when, policyFlags);
        }
    }

    // Copy current touch to last touch in preparation for the next cycle.
    // Keep the button state so we can track edge-triggered button state changes.
@@ -2772,6 +2784,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;
@@ -3215,7 +3233,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
@@ -3224,7 +3243,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
@@ -3237,7 +3260,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;
@@ -3325,27 +3350,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,
@@ -3372,13 +3376,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];
@@ -3433,7 +3473,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
@@ -3468,7 +3508,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.
        //
@@ -3482,11 +3522,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;
        }
@@ -3512,7 +3552,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
                }
@@ -3538,7 +3578,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;
@@ -3575,11 +3615,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
@@ -3587,6 +3628,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();
@@ -3603,7 +3648,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;
@@ -3624,8 +3668,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
            }
        }
@@ -3647,14 +3691,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.
        assert(activeTouchId >= 0);
        // 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: HOVER");
                    LOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f",
                            x - mPointerGesture.tapX,
                            y - mPointerGesture.tapY);
#endif
                }
            } else {
#if DEBUG_GESTURES
                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 =
@@ -3667,35 +3733,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);
        }

        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;
@@ -4098,6 +4178,7 @@ void TouchInputMapper::preparePointerGestures(nsecs_t when,
                coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
    }
#endif
    return true;
}

void TouchInputMapper::moveSpotsLocked() {
+19 −9
Original line number Diff line number Diff line
@@ -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.
+3 −0
Original line number Diff line number Diff line
@@ -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,