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

Commit cacd69a0 authored by Nathaniel R. Lewis's avatar Nathaniel R. Lewis Committed by Chris Ye
Browse files

InputFlinger: Support amplitude control for InputDeviceVibrator

Add support for sending multi-channel rumble amplitudes to input
devices supporting FF_RUMBLE.

Bug: 38511270
Bug: 136215622
Test: Connect a gamepad whose driver supports FF_RUMBLE, find it
      with the android input framework, and do something like this:

      // waveform where rumble magnitude doubles every 2 seconds
      VibrationEffect effect = VibrationEffect.createWaveform(
              new long[] { 2000L, 2000L, 2000L, 2000L, 2000L },
              new int[] { 16, 32, 64, 128, 255 },
              -1);
      inputDevice.getVibrator().vibrate(effect);

Change-Id: I2f059e085c106cbca2372c72d09a9f579d35e4c7
parent dc070322
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ filegroup {
        "InputListener.cpp",
        "InputReaderBase.cpp",
        "InputThread.cpp",
        "VibrationElement.cpp"
    ],
}

+67 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "VibrationElement.h"

#include <android-base/stringprintf.h>

#include <algorithm>
#include <cinttypes>

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 {
    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) {
            dump += ", ";
            dump += std::to_string(channel);
        });
    }
    dump += "]]";
}

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

    // 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;
    }

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

bool VibrationElement::isOn() const {
    return std::any_of(channels.begin(), channels.end(),
                       [](uint16_t channel) { return channel != 0; });
}

} // namespace android
+8 −6
Original line number Diff line number Diff line
@@ -17,23 +17,24 @@
#ifndef _UI_INPUT_READER_BASE_H
#define _UI_INPUT_READER_BASE_H

#include "PointerControllerInterface.h"

#include <input/DisplayViewport.h>
#include <input/Input.h>
#include <input/InputDevice.h>
#include <input/VelocityControl.h>
#include <input/VelocityTracker.h>
#include <stddef.h>
#include <unistd.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>

#include <stddef.h>
#include <unistd.h>
#include <optional>
#include <set>
#include <unordered_map>
#include <vector>

#include "PointerControllerInterface.h"
#include "VibrationElement.h"

// Maximum supported size of a vibration pattern.
// Must be at least 2.
#define MAX_VIBRATE_PATTERN_SIZE 100
@@ -41,6 +42,7 @@
// 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 {

@@ -104,7 +106,7 @@ public:
    virtual void requestRefreshConfiguration(uint32_t changes) = 0;

    /* Controls the vibrator of a particular input device. */
    virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
    virtual void vibrate(int32_t deviceId, const std::vector<VibrationElement>& pattern,
                         ssize_t repeat, int32_t token) = 0;
    virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0;

+41 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _VIBRATION_ELEMENT_H
#define _VIBRATION_ELEMENT_H

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

namespace android {

/*
 * Describes a rumble effect
 */
struct VibrationElement {
    std::chrono::milliseconds duration;
    std::vector<int> channels;

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

} // namespace android

#endif // _VIBRATION_ELEMENT_H
+5 −4
Original line number Diff line number Diff line
@@ -702,7 +702,7 @@ void EventHub::assignDescriptorLocked(InputDeviceIdentifier& identifier) {
          identifier.descriptor.c_str());
}

void EventHub::vibrate(int32_t deviceId, nsecs_t duration) {
void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) {
    AutoMutex _l(mLock);
    Device* device = getDeviceLocked(deviceId);
    if (device != nullptr && device->hasValidFd()) {
@@ -710,9 +710,10 @@ void EventHub::vibrate(int32_t deviceId, nsecs_t duration) {
        memset(&effect, 0, sizeof(effect));
        effect.type = FF_RUMBLE;
        effect.id = device->ffEffectId;
        effect.u.rumble.strong_magnitude = 0xc000;
        effect.u.rumble.weak_magnitude = 0xc000;
        effect.replay.length = (duration + 999999LL) / 1000000LL;
        // 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.replay.length = element.duration.count();
        effect.replay.delay = 0;
        if (ioctl(device->fd, EVIOCSFF, &effect)) {
            ALOGW("Could not upload force feedback effect to device %s due to error %d.",
Loading