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

Commit 7aec5020 authored by Harpreet \"Eli\" Sangha's avatar Harpreet \"Eli\" Sangha
Browse files

vibrator: aidl: Apply Compose API Feedback



- Make Thud and Spin optional due to complexity.
- Make "scale" inclusive of zero, which represents minimum "feelable"
  intensity.
- Update VTS tests appropriately.
- Fix typo in VTS test names.

Bug: 151084263
Test: VTS on Flame, Walleye, and Cuttlefish
Signed-off-by: default avatarHarpreet \"Eli\" Sangha <eliptus@google.com>
Change-Id: Ib0d046be83ee79ab38e0b9c3fb87a41f23879f8b
parent b74b76cc
Loading
Loading
Loading
Loading
+4 −1
Original line number Original line Diff line number Diff line
@@ -23,6 +23,9 @@ parcelable CompositeEffect {
    /* Period of silence preceding primitive. */
    /* Period of silence preceding primitive. */
    int delayMs;
    int delayMs;
    CompositePrimitive primitive;
    CompositePrimitive primitive;
    /* 0.0 (exclusive) - 1.0 (inclusive) */
    /*
     * 0.0 (inclusive) - 1.0 (inclusive),
     * where 0.0 is minimum "feelable" amplitude.
     */
    float scale;
    float scale;
}
}
+16 −0
Original line number Original line Diff line number Diff line
@@ -21,37 +21,53 @@ package android.hardware.vibrator;
enum CompositePrimitive {
enum CompositePrimitive {
    /**
    /**
     * No haptic effect. Used to generate extended delays between primitives.
     * No haptic effect. Used to generate extended delays between primitives.
     *
     * Support is required.
     */
     */
    NOOP,
    NOOP,
    /**
    /**
     * This effect should produce a sharp, crisp click sensation.
     * This effect should produce a sharp, crisp click sensation.
     *
     * Support is required.
     */
     */
    CLICK,
    CLICK,
    /**
    /**
     * A haptic effect that simulates downwards movement with gravity. Often
     * A haptic effect that simulates downwards movement with gravity. Often
     * followed by extra energy of hitting and reverberation to augment
     * followed by extra energy of hitting and reverberation to augment
     * physicality.
     * physicality.
     *
     * Support is optional.
     */
     */
    THUD,
    THUD,
    /**
    /**
     * A haptic effect that simulates spinning momentum.
     * A haptic effect that simulates spinning momentum.
     *
     * Support is optional.
     */
     */
    SPIN,
    SPIN,
    /**
    /**
     * A haptic effect that simulates quick upward movement against gravity.
     * A haptic effect that simulates quick upward movement against gravity.
     *
     * Support is required.
     */
     */
    QUICK_RISE,
    QUICK_RISE,
    /**
    /**
     * A haptic effect that simulates slow upward movement against gravity.
     * A haptic effect that simulates slow upward movement against gravity.
     *
     * Support is required.
     */
     */
    SLOW_RISE,
    SLOW_RISE,
    /**
    /**
     * A haptic effect that simulates quick downwards movement with gravity.
     * A haptic effect that simulates quick downwards movement with gravity.
     *
     * Support is required.
     */
     */
    QUICK_FALL,
    QUICK_FALL,
    /**
    /**
     * This very short effect should produce a light crisp sensation intended
     * This very short effect should produce a light crisp sensation intended
     * to be used repetitively for dynamic feedback.
     * to be used repetitively for dynamic feedback.
     *
     * Support is required.
     */
     */
    LIGHT_TICK,
    LIGHT_TICK,
}
}
+2 −2
Original line number Original line Diff line number Diff line
@@ -161,8 +161,8 @@ interface IVibrator {
     * List of supported effect primitive.
     * List of supported effect primitive.
     *
     *
     * Return the effect primitives which are supported by the compose API.
     * Return the effect primitives which are supported by the compose API.
     * Implementations are expected to support all primitives of the interface
     * Implementations are expected to support all required primitives of the
     * version that they implement.
     * interface version that they implement (see primitive definitions).
     */
     */
    CompositePrimitive[] getSupportedPrimitives();
    CompositePrimitive[] getSupportedPrimitives();


+1 −1
Original line number Original line Diff line number Diff line
@@ -146,7 +146,7 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composi
        if (e.delayMs > kComposeDelayMaxMs) {
        if (e.delayMs > kComposeDelayMaxMs) {
            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
        }
        }
        if (e.scale <= 0.0f || e.scale > 1.0f) {
        if (e.scale < 0.0f || e.scale > 1.0f) {
            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
        }
        }
        if (std::find(supported.begin(), supported.end(), e.primitive) == supported.end()) {
        if (std::find(supported.begin(), supported.end(), e.primitive) == supported.end()) {
+74 −10
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@
#include <binder/IServiceManager.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <binder/ProcessState.h>


#include <cmath>
#include <future>
#include <future>


using android::ProcessState;
using android::ProcessState;
@@ -53,6 +54,11 @@ const std::vector<CompositePrimitive> kCompositePrimitives{
        android::enum_range<CompositePrimitive>().begin(),
        android::enum_range<CompositePrimitive>().begin(),
        android::enum_range<CompositePrimitive>().end()};
        android::enum_range<CompositePrimitive>().end()};


const std::vector<CompositePrimitive> kOptionalPrimitives = {
        CompositePrimitive::THUD,
        CompositePrimitive::SPIN,
};

const std::vector<CompositePrimitive> kInvalidPrimitives = {
const std::vector<CompositePrimitive> kInvalidPrimitives = {
        static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.front()) - 1),
        static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.front()) - 1),
        static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.back()) + 1),
        static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.back()) + 1),
@@ -264,38 +270,56 @@ TEST_P(VibratorAidl, GetSupportedPrimitives) {


        EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode());
        EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode());


        std::sort(supported.begin(), supported.end());
        for (auto primitive : kCompositePrimitives) {
            bool isPrimitiveSupported =
                    std::find(supported.begin(), supported.end(), primitive) != supported.end();
            bool isPrimitiveOptional =
                    std::find(kOptionalPrimitives.begin(), kOptionalPrimitives.end(), primitive) !=
                    kOptionalPrimitives.end();


        EXPECT_EQ(kCompositePrimitives, supported);
            EXPECT_TRUE(isPrimitiveSupported || isPrimitiveOptional) << toString(primitive);
        }
    }
    }
}
}


TEST_P(VibratorAidl, GetPrimitiveDuration) {
TEST_P(VibratorAidl, GetPrimitiveDuration) {
    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
        int32_t duration;
        std::vector<CompositePrimitive> supported;
        ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());


        for (auto primitive : kCompositePrimitives) {
        for (auto primitive : kCompositePrimitives) {
            EXPECT_EQ(Status::EX_NONE,
            bool isPrimitiveSupported =
                      vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode());
                    std::find(supported.begin(), supported.end(), primitive) != supported.end();
            int32_t duration;

            Status status = vibrator->getPrimitiveDuration(primitive, &duration);

            if (isPrimitiveSupported) {
                EXPECT_EQ(Status::EX_NONE, status.exceptionCode());
            } else {
                EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode());
            }
        }
        }
    }
    }
}
}


TEST_P(VibratorAidl, ComposeValidPrimitives) {
TEST_P(VibratorAidl, ComposeValidPrimitives) {
    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
        std::vector<CompositePrimitive> supported;
        int32_t maxDelay, maxSize;
        int32_t maxDelay, maxSize;


        ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
        EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode());
        EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode());
        EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode());
        EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode());


        std::vector<CompositeEffect> composite;
        std::vector<CompositeEffect> composite;


        for (auto primitive : kCompositePrimitives) {
        for (auto primitive : supported) {
            CompositeEffect effect;
            CompositeEffect effect;


            effect.delayMs = std::rand() % (maxDelay + 1);
            effect.delayMs = std::rand() % (maxDelay + 1);
            effect.primitive = primitive;
            effect.primitive = primitive;
            effect.scale = static_cast<float>(std::rand()) / RAND_MAX ?: 1.0f;
            effect.scale = static_cast<float>(std::rand()) / RAND_MAX;
            composite.emplace_back(effect);
            composite.emplace_back(effect);


            if (composite.size() == maxSize) {
            if (composite.size() == maxSize) {
@@ -314,7 +338,21 @@ TEST_P(VibratorAidl, ComposeValidPrimitives) {


TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) {
TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) {
    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
        for (auto primitive : kInvalidPrimitives) {
        auto unsupported = kInvalidPrimitives;
        std::vector<CompositePrimitive> supported;

        ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());

        for (auto primitive : kCompositePrimitives) {
            bool isPrimitiveSupported =
                    std::find(supported.begin(), supported.end(), primitive) != supported.end();

            if (!isPrimitiveSupported) {
                unsupported.push_back(primitive);
            }
        }

        for (auto primitive : unsupported) {
            std::vector<CompositeEffect> composite(1);
            std::vector<CompositeEffect> composite(1);


            for (auto& effect : composite) {
            for (auto& effect : composite) {
@@ -329,7 +367,33 @@ TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) {
    }
    }
}
}


TEST_P(VibratorAidl, CompseDelayBoundary) {
TEST_P(VibratorAidl, ComposeScaleBoundary) {
    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
        std::vector<CompositeEffect> composite(1);
        CompositeEffect& effect = composite[0];

        effect.delayMs = 0;
        effect.primitive = CompositePrimitive::CLICK;

        effect.scale = std::nextafter(0.0f, -1.0f);
        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
                  vibrator->compose(composite, nullptr).exceptionCode());

        effect.scale = 0.0f;
        EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());

        effect.scale = 1.0f;
        EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());

        effect.scale = std::nextafter(1.0f, 2.0f);
        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
                  vibrator->compose(composite, nullptr).exceptionCode());

        vibrator->off();
    }
}

TEST_P(VibratorAidl, ComposeDelayBoundary) {
    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
        int32_t maxDelay;
        int32_t maxDelay;


@@ -354,7 +418,7 @@ TEST_P(VibratorAidl, CompseDelayBoundary) {
    }
    }
}
}


TEST_P(VibratorAidl, CompseSizeBoundary) {
TEST_P(VibratorAidl, ComposeSizeBoundary) {
    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
        int32_t maxSize;
        int32_t maxSize;