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

Commit 538881e1 authored by Jeff Brown's avatar Jeff Brown
Browse files

Touch pad UX improvements.

Fade the pointer spot when swiping or performing a freeform
gesture.

Support configuring the gesture mode in the device IDC file.

Added workaround for devices that report individual finger
movements one at a time instead of all at once.

Bug: 4124987
Change-Id: I44628b00382ad59306e4ec5c4717d69cc6fbebb8
parent 2cb7981e
Loading
Loading
Loading
Loading
+98 −25
Original line number Diff line number Diff line
@@ -1627,7 +1627,7 @@ void CursorInputMapper::sync(nsecs_t when) {
                    mPointerController->setButtonState(mLocked.buttonState);
                }

                mPointerController->unfade();
                mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
            }

            float x, y;
@@ -1686,7 +1686,7 @@ void CursorInputMapper::fadePointer() {
    { // acquire lock
        AutoMutex _l(mLock);
        if (mPointerController != NULL) {
            mPointerController->fade();
            mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
        }
    } // release lock
}
@@ -1873,10 +1873,22 @@ void TouchInputMapper::configureParameters() {
    mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents();
    mParameters.virtualKeyQuietTime = getPolicy()->getVirtualKeyQuietTime();

    // TODO: Make this configurable.
    //mParameters.gestureMode = Parameters::GESTURE_MODE_POINTER;
    // TODO: select the default gesture mode based on whether the device supports
    // distinct multitouch
    mParameters.gestureMode = Parameters::GESTURE_MODE_SPOTS;

    String8 gestureModeString;
    if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"),
            gestureModeString)) {
        if (gestureModeString == "pointer") {
            mParameters.gestureMode = Parameters::GESTURE_MODE_POINTER;
        } else if (gestureModeString == "spots") {
            mParameters.gestureMode = Parameters::GESTURE_MODE_SPOTS;
        } else if (gestureModeString != "default") {
            LOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string());
        }
    }

    if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X)
            || getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) {
        // The device is a cursor device with a touch pad attached.
@@ -1897,7 +1909,7 @@ void TouchInputMapper::configureParameters() {
            mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
        } else if (deviceTypeString == "pointer") {
            mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
        } else {
        } else if (deviceTypeString != "default") {
            LOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
        }
    }
@@ -1915,6 +1927,17 @@ void TouchInputMapper::configureParameters() {
void TouchInputMapper::dumpParameters(String8& dump) {
    dump.append(INDENT3 "Parameters:\n");

    switch (mParameters.gestureMode) {
    case Parameters::GESTURE_MODE_POINTER:
        dump.append(INDENT4 "GestureMode: pointer\n");
        break;
    case Parameters::GESTURE_MODE_SPOTS:
        dump.append(INDENT4 "GestureMode: spots\n");
        break;
    default:
        assert(false);
    }

    switch (mParameters.deviceType) {
    case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
        dump.append(INDENT4 "DeviceType: touchScreen\n");
@@ -3251,10 +3274,36 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
        return;
    }

    // Show the pointer if needed.
    if (mPointerGesture.currentGestureMode != PointerGesture::NEUTRAL
            && mPointerGesture.currentGestureMode != PointerGesture::QUIET) {
        mPointerController->unfade();
    // Show or hide the pointer if needed.
    switch (mPointerGesture.currentGestureMode) {
    case PointerGesture::NEUTRAL:
    case PointerGesture::QUIET:
        if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS
                && (mPointerGesture.lastGestureMode == PointerGesture::SWIPE
                        || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM)) {
            // Remind the user of where the pointer is after finishing a gesture with spots.
            mPointerController->unfade(PointerControllerInterface::TRANSITION_GRADUAL);
        }
        break;
    case PointerGesture::TAP:
    case PointerGesture::TAP_DRAG:
    case PointerGesture::BUTTON_CLICK_OR_DRAG:
    case PointerGesture::HOVER:
    case PointerGesture::PRESS:
        // Unfade the pointer when the current gesture manipulates the
        // area directly under the pointer.
        mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
        break;
    case PointerGesture::SWIPE:
    case PointerGesture::FREEFORM:
        // Fade the pointer when the current gesture manipulates a different
        // area and there are spots to guide the user experience.
        if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
            mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
        } else {
            mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
        }
        break;
    }

    // Send events!
@@ -3808,6 +3857,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
            *outFinishPreviousGesture = true;
            mPointerGesture.currentGestureMode = PointerGesture::PRESS;
            mPointerGesture.activeGestureId = 0;
            mPointerGesture.referenceIdBits.clear();

            if (settled && mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS
                    && mLastTouch.idBits.hasBit(mPointerGesture.activeTouchId)) {
@@ -3938,6 +3988,17 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
            }
        }

        // Clear the reference deltas for fingers not yet included in the reference calculation.
        for (BitSet32 idBits(mCurrentTouch.idBits.value & ~mPointerGesture.referenceIdBits.value);
                !idBits.isEmpty(); ) {
            uint32_t id = idBits.firstMarkedBit();
            idBits.clearBit(id);

            mPointerGesture.referenceDeltas[id].dx = 0;
            mPointerGesture.referenceDeltas[id].dy = 0;
        }
        mPointerGesture.referenceIdBits = mCurrentTouch.idBits;

        // Move the reference points based on the overall group motion of the fingers.
        // The objective is to calculate a vector delta that is common to the movement
        // of all fingers.
@@ -3951,18 +4012,29 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,

                const PointerData& cpd = mCurrentTouch.pointers[mCurrentTouch.idToIndex[id]];
                const PointerData& lpd = mLastTouch.pointers[mLastTouch.idToIndex[id]];
                float deltaX = cpd.x - lpd.x;
                float deltaY = cpd.y - lpd.y;
                PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
                delta.dx += cpd.x - lpd.x;
                delta.dy += cpd.y - lpd.y;

                if (first) {
                    commonDeltaX = deltaX;
                    commonDeltaY = deltaY;
                    commonDeltaX = delta.dx;
                    commonDeltaY = delta.dy;
                } else {
                    commonDeltaX = calculateCommonVector(commonDeltaX, deltaX);
                    commonDeltaY = calculateCommonVector(commonDeltaY, deltaY);
                    commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx);
                    commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy);
                }
            }

            if (commonDeltaX || commonDeltaY) {
                for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) {
                    uint32_t id = idBits.firstMarkedBit();
                    idBits.clearBit(id);

                    PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
                    delta.dx = 0;
                    delta.dy = 0;
                }

                mPointerGesture.referenceTouchX += commonDeltaX;
                mPointerGesture.referenceTouchY += commonDeltaY;
                mPointerGesture.referenceGestureX +=
@@ -3973,6 +4045,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
                        &mPointerGesture.referenceGestureX,
                        &mPointerGesture.referenceGestureY);
            }
        }

        // Report gestures.
        if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) {
@@ -4255,7 +4328,7 @@ void TouchInputMapper::fadePointer() {
    { // acquire lock
        AutoMutex _l(mLock);
        if (mPointerController != NULL) {
            mPointerController->fade();
            mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
        }
    } // release lock
}
+8 −0
Original line number Diff line number Diff line
@@ -1021,6 +1021,14 @@ private:
        float referenceGestureX;  // reference gesture X/Y coordinates in pixels
        float referenceGestureY;

        // Distance that each pointer has traveled which has not yet been
        // subsumed into the reference gesture position.
        BitSet32 referenceIdBits;
        struct Delta {
            float dx, dy;
        };
        Delta referenceDeltas[MAX_POINTER_ID + 1];

        // Describes how touch ids are mapped to gesture ids for freeform gestures.
        uint32_t freeformTouchToGestureIdMap[MAX_POINTER_ID + 1];

+37 −19
Original line number Diff line number Diff line
@@ -69,10 +69,10 @@ PointerController::PointerController(const sp<PointerControllerPolicyInterface>&

    mLocked.inactivityTimeout = INACTIVITY_TIMEOUT_NORMAL;

    mLocked.pointerIsFading = true; // keep the pointer initially faded
    mLocked.pointerFadeDirection = 0;
    mLocked.pointerX = 0;
    mLocked.pointerY = 0;
    mLocked.pointerAlpha = 0.0f;
    mLocked.pointerAlpha = 0.0f; // pointer is initially faded
    mLocked.pointerSprite = mSpriteController->createSprite();
    mLocked.pointerIconChanged = false;

@@ -191,23 +191,37 @@ void PointerController::getPosition(float* outX, float* outY) const {
    *outY = mLocked.pointerY;
}

void PointerController::fade() {
void PointerController::fade(Transition transition) {
    AutoMutex _l(mLock);

    sendImmediateInactivityTimeoutLocked();
    // Remove the inactivity timeout, since we are fading now.
    removeInactivityTimeoutLocked();

    // Start fading.
    if (transition == TRANSITION_IMMEDIATE) {
        mLocked.pointerFadeDirection = 0;
        mLocked.pointerAlpha = 0.0f;
        updatePointerLocked();
    } else {
        mLocked.pointerFadeDirection = -1;
        startAnimationLocked();
    }
}

void PointerController::unfade() {
void PointerController::unfade(Transition transition) {
    AutoMutex _l(mLock);

    // Always reset the inactivity timer.
    resetInactivityTimeoutLocked();

    // Unfade immediately if needed.
    if (mLocked.pointerIsFading) {
        mLocked.pointerIsFading = false;
    // Start unfading.
    if (transition == TRANSITION_IMMEDIATE) {
        mLocked.pointerFadeDirection = 0;
        mLocked.pointerAlpha = 1.0f;
        updatePointerLocked();
    } else {
        mLocked.pointerFadeDirection = 1;
        startAnimationLocked();
    }
}

@@ -401,10 +415,20 @@ void PointerController::doAnimate() {
    nsecs_t frameDelay = systemTime(SYSTEM_TIME_MONOTONIC) - mLocked.animationTime;

    // Animate pointer fade.
    if (mLocked.pointerIsFading) {
    if (mLocked.pointerFadeDirection < 0) {
        mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION;
        if (mLocked.pointerAlpha <= 0) {
            mLocked.pointerAlpha = 0;
        if (mLocked.pointerAlpha <= 0.0f) {
            mLocked.pointerAlpha = 0.0f;
            mLocked.pointerFadeDirection = 0;
        } else {
            keepAnimating = true;
        }
        updatePointerLocked();
    } else if (mLocked.pointerFadeDirection > 0) {
        mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION;
        if (mLocked.pointerAlpha >= 1.0f) {
            mLocked.pointerAlpha = 1.0f;
            mLocked.pointerFadeDirection = 0;
        } else {
            keepAnimating = true;
        }
@@ -432,12 +456,7 @@ void PointerController::doAnimate() {
}

void PointerController::doInactivityTimeout() {
    AutoMutex _l(mLock);

    if (!mLocked.pointerIsFading) {
        mLocked.pointerIsFading = true;
        startAnimationLocked();
    }
    fade(TRANSITION_GRADUAL);
}

void PointerController::startAnimationLocked() {
@@ -456,9 +475,8 @@ void PointerController::resetInactivityTimeoutLocked() {
    mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT);
}

void PointerController::sendImmediateInactivityTimeoutLocked() {
void PointerController::removeInactivityTimeoutLocked() {
    mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
    mLooper->sendMessage(mHandler, MSG_INACTIVITY_TIMEOUT);
}

void PointerController::updatePointerLocked() {
+13 −6
Original line number Diff line number Diff line
@@ -64,14 +64,21 @@ public:
    /* Gets the absolute location of the pointer. */
    virtual void getPosition(float* outX, float* outY) const = 0;

    enum Transition {
        // Fade/unfade immediately.
        TRANSITION_IMMEDIATE,
        // Fade/unfade gradually.
        TRANSITION_GRADUAL,
    };

    /* Fades the pointer out now. */
    virtual void fade() = 0;
    virtual void fade(Transition transition) = 0;

    /* Makes the pointer visible if it has faded out.
     * The pointer never unfades itself automatically.  This method must be called
     * by the client whenever the pointer is moved or a button is pressed and it
     * wants to ensure that the pointer becomes visible again. */
    virtual void unfade() = 0;
    virtual void unfade(Transition transition) = 0;

    enum Presentation {
        // Show the mouse pointer.
@@ -187,8 +194,8 @@ public:
    virtual uint32_t getButtonState() const;
    virtual void setPosition(float x, float y);
    virtual void getPosition(float* outX, float* outY) const;
    virtual void fade();
    virtual void unfade();
    virtual void fade(Transition transition);
    virtual void unfade(Transition transition);

    virtual void setPresentation(Presentation presentation);
    virtual void setSpots(SpotGesture spotGesture,
@@ -250,7 +257,7 @@ private:
        Presentation presentation;
        bool presentationChanged;

        bool pointerIsFading;
        int32_t pointerFadeDirection;
        float pointerX;
        float pointerY;
        float pointerAlpha;
@@ -274,7 +281,7 @@ private:
    void startAnimationLocked();

    void resetInactivityTimeoutLocked();
    void sendImmediateInactivityTimeoutLocked();
    void removeInactivityTimeoutLocked();
    void updatePointerLocked();

    Spot* getSpotLocked(uint32_t id);
+2 −2
Original line number Diff line number Diff line
@@ -92,10 +92,10 @@ private:
        *outY = 0;
    }

    virtual void fade() {
    virtual void fade(Transition transition) {
    }

    virtual void unfade() {
    virtual void unfade(Transition transition) {
    }

    virtual void setPresentation(Presentation presentation) {