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

Commit 2cd8035e authored by Ahmad Khalil's avatar Ahmad Khalil
Browse files

Add adaptive haptics scaling to external vibrations

We've converted HapticScale into a struct which includes both scale
level and adaptive haptics scale. The adaptive haptics scale is now included in the process of scaling vibrations.

Bug: 305957324
Test: N/A
Change-Id: Ic46f11812e2599da6ec7f8363932a0d9368e7157
parent f8680e6d
Loading
Loading
Loading
Loading
+30 −18
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@
#include <vibrator/ExternalVibration.h>
#include <vibrator/ExternalVibrationUtils.h>

#include <android/os/IExternalVibratorService.h>
#include <android/os/ExternalVibrationScale.h>
#include <binder/Parcel.h>
#include <log/log.h>
#include <utils/Errors.h>
@@ -65,24 +65,36 @@ inline bool ExternalVibration::operator==(const ExternalVibration& rhs) const {
    return mToken == rhs.mToken;
}

os::HapticScale ExternalVibration::externalVibrationScaleToHapticScale(int externalVibrationScale) {
    switch (externalVibrationScale) {
        case IExternalVibratorService::SCALE_MUTE:
            return os::HapticScale::MUTE;
        case IExternalVibratorService::SCALE_VERY_LOW:
            return os::HapticScale::VERY_LOW;
        case IExternalVibratorService::SCALE_LOW:
            return os::HapticScale::LOW;
        case IExternalVibratorService::SCALE_NONE:
            return os::HapticScale::NONE;
        case IExternalVibratorService::SCALE_HIGH:
            return os::HapticScale::HIGH;
        case IExternalVibratorService::SCALE_VERY_HIGH:
            return os::HapticScale::VERY_HIGH;
os::HapticScale ExternalVibration::externalVibrationScaleToHapticScale(
        os::ExternalVibrationScale externalVibrationScale) {
    os::HapticLevel scaleLevel = os::HapticLevel::NONE;

    switch (externalVibrationScale.scaleLevel) {
        case os::ExternalVibrationScale::ScaleLevel::SCALE_MUTE:
            scaleLevel = os::HapticLevel::MUTE;
            break;
        case os::ExternalVibrationScale::ScaleLevel::SCALE_VERY_LOW:
            scaleLevel = os::HapticLevel::VERY_LOW;
            break;
        case os::ExternalVibrationScale::ScaleLevel::SCALE_LOW:
            scaleLevel = os::HapticLevel::LOW;
            break;
        case os::ExternalVibrationScale::ScaleLevel::SCALE_NONE:
            scaleLevel = os::HapticLevel::NONE;
            break;
        case os::ExternalVibrationScale::ScaleLevel::SCALE_HIGH:
            scaleLevel = os::HapticLevel::HIGH;
            break;
        case os::ExternalVibrationScale::ScaleLevel::SCALE_VERY_HIGH:
            scaleLevel = os::HapticLevel::VERY_HIGH;
            break;
        default:
          ALOGE("Unknown ExternalVibrationScale %d, not applying scaling", externalVibrationScale);
          return os::HapticScale::NONE;
            ALOGE("Unknown ExternalVibrationScale %d, not applying scaling",
                  externalVibrationScale.scaleLevel);
    }

    return {/*level=*/scaleLevel, /*adaptiveScaleFactor=*/
                      externalVibrationScale.adaptiveHapticsScale};
}

} // namespace os
+36 −27
Original line number Diff line number Diff line
@@ -26,30 +26,30 @@ static constexpr float HAPTIC_SCALE_VERY_LOW_RATIO = 2.0f / 3.0f;
static constexpr float HAPTIC_SCALE_LOW_RATIO = 3.0f / 4.0f;
static constexpr float HAPTIC_MAX_AMPLITUDE_FLOAT = 1.0f;

float getHapticScaleGamma(HapticScale scale) {
    switch (scale) {
    case HapticScale::VERY_LOW:
float getHapticScaleGamma(HapticLevel level) {
    switch (level) {
    case HapticLevel::VERY_LOW:
        return 2.0f;
    case HapticScale::LOW:
    case HapticLevel::LOW:
        return 1.5f;
    case HapticScale::HIGH:
    case HapticLevel::HIGH:
        return 0.5f;
    case HapticScale::VERY_HIGH:
    case HapticLevel::VERY_HIGH:
        return 0.25f;
    default:
        return 1.0f;
    }
}

float getHapticMaxAmplitudeRatio(HapticScale scale) {
    switch (scale) {
    case HapticScale::VERY_LOW:
float getHapticMaxAmplitudeRatio(HapticLevel level) {
    switch (level) {
    case HapticLevel::VERY_LOW:
        return HAPTIC_SCALE_VERY_LOW_RATIO;
    case HapticScale::LOW:
    case HapticLevel::LOW:
        return HAPTIC_SCALE_LOW_RATIO;
    case HapticScale::NONE:
    case HapticScale::HIGH:
    case HapticScale::VERY_HIGH:
    case HapticLevel::NONE:
    case HapticLevel::HIGH:
    case HapticLevel::VERY_HIGH:
        return 1.0f;
    default:
        return 0.0f;
@@ -57,20 +57,29 @@ float getHapticMaxAmplitudeRatio(HapticScale scale) {
}

void applyHapticScale(float* buffer, size_t length, HapticScale scale) {
    if (scale == HapticScale::MUTE) {
    if (scale.isScaleMute()) {
        memset(buffer, 0, length * sizeof(float));
        return;
    }
    if (scale == HapticScale::NONE) {
    if (scale.isScaleNone()) {
        return;
    }
    float gamma = getHapticScaleGamma(scale);
    float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(scale);
    HapticLevel hapticLevel = scale.getLevel();
    float adaptiveScaleFactor = scale.getAdaptiveScaleFactor();
    float gamma = getHapticScaleGamma(hapticLevel);
    float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(hapticLevel);

    for (size_t i = 0; i < length; i++) {
        if (hapticLevel != HapticLevel::NONE) {
            float sign = buffer[i] >= 0 ? 1.0 : -1.0;
            buffer[i] = powf(fabsf(buffer[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma)
                        * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign;
        }

        if (adaptiveScaleFactor != 1.0f) {
            buffer[i] *= adaptiveScaleFactor;
        }
    }
}

void clipHapticData(float* buffer, size_t length, float limit) {
@@ -89,13 +98,13 @@ void clipHapticData(float* buffer, size_t length, float limit) {
} // namespace

bool isValidHapticScale(HapticScale scale) {
    switch (scale) {
    case HapticScale::MUTE:
    case HapticScale::VERY_LOW:
    case HapticScale::LOW:
    case HapticScale::NONE:
    case HapticScale::HIGH:
    case HapticScale::VERY_HIGH:
    switch (scale.getLevel()) {
    case HapticLevel::MUTE:
    case HapticLevel::VERY_LOW:
    case HapticLevel::LOW:
    case HapticLevel::NONE:
    case HapticLevel::HIGH:
    case HapticLevel::VERY_HIGH:
        return true;
    }
    return false;
+4 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <system/audio.h>
#include <utils/RefBase.h>
#include <vibrator/ExternalVibrationUtils.h>
#include <android/os/ExternalVibrationScale.h>

namespace android {
namespace os {
@@ -45,10 +46,11 @@ public :
    audio_attributes_t getAudioAttributes() const { return mAttrs; }
    sp<IExternalVibrationController> getController() { return mController; }

    /* Converts the scale from non-public ExternalVibrationService into the HapticScale
    /* Converts the scale from non-public ExternalVibrationService into the HapticScaleLevel
     * used by the utils.
     */
    static os::HapticScale externalVibrationScaleToHapticScale(int externalVibrationScale);
    static os::HapticScale externalVibrationScaleToHapticScale(
            os::ExternalVibrationScale externalVibrationScale);

private:
    int32_t mUid;
+34 −3
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@

namespace android::os {

enum class HapticScale {
enum class HapticLevel {
    MUTE = -100,
    VERY_LOW = -2,
    LOW = -1,
@@ -28,10 +28,41 @@ enum class HapticScale {
    VERY_HIGH = 2,
};

class HapticScale {
private:
HapticLevel mLevel = HapticLevel::NONE;
float mAdaptiveScaleFactor = 1.0f;

public:
constexpr HapticScale(HapticLevel level, float adaptiveScaleFactor)
    : mLevel(level), mAdaptiveScaleFactor(adaptiveScaleFactor) {}
constexpr HapticScale(HapticLevel level) : mLevel(level) {}
constexpr HapticScale() {}

HapticLevel getLevel() const { return mLevel; }
float getAdaptiveScaleFactor() const { return mAdaptiveScaleFactor; }

bool operator==(const HapticScale& other) const {
    return mLevel == other.mLevel && mAdaptiveScaleFactor == other.mAdaptiveScaleFactor;
}

bool isScaleNone() const {
    return mLevel == HapticLevel::NONE && mAdaptiveScaleFactor == 1.0f;
}

bool isScaleMute() const {
    return mLevel == HapticLevel::MUTE;
}

static HapticScale mute() {
    return {/*level=*/os::HapticLevel::MUTE};
}
};

bool isValidHapticScale(HapticScale scale);

/* Scales the haptic data in given buffer using the selected HapticScale and ensuring no absolute
 * value will be larger than the absolute of given limit.
/* Scales the haptic data in given buffer using the selected HapticScaleLevel and ensuring no
 * absolute value will be larger than the absolute of given limit.
 * The limit will be ignored if it is NaN or zero.
 */
void scaleHapticData(float* buffer, size_t length, HapticScale scale, float limit);