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

Commit 6393a269 authored by Chris Ye's avatar Chris Ye
Browse files

Refactor input device rumble support.

Change VibrationElement to fixed size array of uint8_t.
Move default amplitude handling to Java.
Address previous code review comments.

Bug: 136215622
Test: Connect game controller with rumble support and play game for
force feedback effect.

Change-Id: Ife7294bd829a2ca88354ffa09f523e43a1bc26dc
parent 3b2e768f
Loading
Loading
Loading
Loading
+11 −22
Original line number Diff line number Diff line
@@ -25,38 +25,27 @@ using android::base::StringPrintf;

namespace android {

// The sentinel to use the default amplitude
static const int DEFAULT_AMPLITUDE = -1;

// The vibration magnitude for the "DEFAULT_AMPLITUDE" magnitude constant.
static const uint16_t DEFAULT_MAGNITUDE = 0xc000;

void VibrationElement::dump(std::string& dump) const {
const std::string VibrationElement::toString() const {
    std::string dump;
    dump += StringPrintf("[duration=%lldms, channels=[", duration.count());

    if (channels.size()) {
        dump += std::to_string(channels[0]);
        std::for_each(channels.begin() + 1, channels.end(), [&dump](int channel) {
    for (auto it = channels.begin(); it != channels.end(); ++it) {
        dump += std::to_string(*it);
        if (std::next(it) != channels.end()) {
            dump += ", ";
            dump += std::to_string(channel);
        });
        }
    dump += "]]";
    }

uint16_t VibrationElement::getChannel(int id) const {
    if (id >= (int)channels.size()) {
        return 0;
    dump += "]]";
    return dump;
}

    // android framework uses DEFAULT_AMPLITUDE to signal that the vibration
    // should use some built-in default value, denoted here as DEFAULT_MAGNITUDE
    if (channels[id] == DEFAULT_AMPLITUDE) {
        return DEFAULT_MAGNITUDE;
uint16_t VibrationElement::getMagnitude(size_t channelIdx) const {
    if (channelIdx >= channels.size()) {
        return 0;
    }

    // convert range [0,255] to [0,65535] (android framework to linux ff ranges)
    return ((uint16_t)channels[id]) << 8;
    return static_cast<uint16_t>(channels[channelIdx]) << 8;
}

bool VibrationElement::isOn() const {
+0 −5
Original line number Diff line number Diff line
@@ -39,11 +39,6 @@
// Must be at least 2.
#define MAX_VIBRATE_PATTERN_SIZE 100

// Maximum allowable delay value in a vibration pattern before
// which the delay will be truncated.
#define MAX_VIBRATE_PATTERN_DELAY_NSECS (1000000 * 1000000000LL)
#define MAX_VIBRATE_PATTERN_DELAY_MSECS (1000000 * 1000LL)

namespace android {

// --- InputReaderInterface ---
+7 −4
Original line number Diff line number Diff line
@@ -17,22 +17,25 @@
#ifndef _VIBRATION_ELEMENT_H
#define _VIBRATION_ELEMENT_H

#include <array>
#include <chrono>
#include <cstdint>
#include <string>
#include <vector>

namespace android {

// evdev FF_RUMBLE effect only supports two channels of vibration.
constexpr size_t CHANNEL_SIZE = 2;
/*
 * Describes a rumble effect
 */
struct VibrationElement {
    std::chrono::milliseconds duration;
    std::vector<int> channels;
    // Channel amplitude range 0-255.
    std::array<uint8_t, CHANNEL_SIZE> channels = {0, 0};

    void dump(std::string& dump) const;
    uint16_t getChannel(int id) const;
    const std::string toString() const;
    uint16_t getMagnitude(size_t channelIndex) const;
    bool isOn() const;
};

+5 −2
Original line number Diff line number Diff line
@@ -61,6 +61,9 @@ static const char* DEVICE_PATH = "/dev/input";
// v4l2 devices go directly into /dev
static const char* VIDEO_DEVICE_PATH = "/dev";

static constexpr size_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0;
static constexpr size_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1;

static inline const char* toString(bool value) {
    return value ? "true" : "false";
}
@@ -834,8 +837,8 @@ void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) {
        effect.type = FF_RUMBLE;
        effect.id = device->ffEffectId;
        // evdev FF_RUMBLE effect only supports two channels of vibration.
        effect.u.rumble.strong_magnitude = element.getChannel(0);
        effect.u.rumble.weak_magnitude = element.getChannel(1);
        effect.u.rumble.strong_magnitude = element.getMagnitude(FF_STRONG_MAGNITUDE_CHANNEL_IDX);
        effect.u.rumble.weak_magnitude = element.getMagnitude(FF_WEAK_MAGNITUDE_CHANNEL_IDX);
        effect.replay.length = element.duration.count();
        effect.replay.delay = 0;
        if (ioctl(device->fd, EVIOCSFF, &effect)) {
+6 −7
Original line number Diff line number Diff line
@@ -91,8 +91,7 @@ void VibratorInputMapper::nextStep() {
    const VibrationElement& element = mPattern[mIndex];
    if (element.isOn()) {
#if DEBUG_VIBRATOR
        std::string description;
        element.dump(description);
        std::string description = element.toString();
        ALOGD("nextStep: sending vibrate deviceId=%d, element=%s", getDeviceId(),
              description.c_str());
#endif
@@ -135,13 +134,13 @@ void VibratorInputMapper::dump(std::string& dump) {
void VibratorInputMapper::dumpPattern(std::string& dump) const {
    dump += "[";

    if (mPattern.size() > 0) {
        mPattern[0].dump(dump);
        std::for_each(mPattern.begin() + 1, mPattern.end(), [&dump](const auto& element) {
    for (auto it = mPattern.begin(); it != mPattern.end(); ++it) {
        dump += it->toString();
        if (std::next(it) != mPattern.end()) {
            dump += ", ";
            element.dump(dump);
        });
        }
    }

    dump += "]";
}