mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 05:49:27 +00:00
Merge "Update HAL with new PWLE V2 APIs" into main
This commit is contained in:
@@ -59,6 +59,11 @@ interface IVibrator {
|
||||
android.hardware.vibrator.Braking[] getSupportedBraking();
|
||||
void composePwle(in android.hardware.vibrator.PrimitivePwle[] composite, in android.hardware.vibrator.IVibratorCallback callback);
|
||||
void performVendorEffect(in android.hardware.vibrator.VendorEffect vendorEffect, in android.hardware.vibrator.IVibratorCallback callback);
|
||||
List<android.hardware.vibrator.PwleV2OutputMapEntry> getPwleV2FrequencyToOutputAccelerationMap();
|
||||
int getPwleV2PrimitiveDurationMaxMillis();
|
||||
int getPwleV2CompositionSizeMax();
|
||||
int getPwleV2PrimitiveDurationMinMillis();
|
||||
void composePwleV2(in android.hardware.vibrator.PwleV2Primitive[] composite, in android.hardware.vibrator.IVibratorCallback callback);
|
||||
const int CAP_ON_CALLBACK = (1 << 0) /* 1 */;
|
||||
const int CAP_PERFORM_CALLBACK = (1 << 1) /* 2 */;
|
||||
const int CAP_AMPLITUDE_CONTROL = (1 << 2) /* 4 */;
|
||||
@@ -71,4 +76,5 @@ interface IVibrator {
|
||||
const int CAP_FREQUENCY_CONTROL = (1 << 9) /* 512 */;
|
||||
const int CAP_COMPOSE_PWLE_EFFECTS = (1 << 10) /* 1024 */;
|
||||
const int CAP_PERFORM_VENDOR_EFFECTS = (1 << 11) /* 2048 */;
|
||||
const int CAP_COMPOSE_PWLE_EFFECTS_V2 = (1 << 12) /* 4096 */;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
|
||||
// two cases:
|
||||
// 1). this is a frozen version file - do not edit this in any case.
|
||||
// 2). this is a 'current' file. If you make a backwards compatible change to
|
||||
// the interface (from the latest frozen version), the build system will
|
||||
// prompt you to update this file with `m <name>-update-api`.
|
||||
//
|
||||
// You must not make a backward incompatible change to any AIDL file built
|
||||
// with the aidl_interface module type with versions property set. The module
|
||||
// type is used to build AIDL files in a way that they can be used across
|
||||
// independently updatable components of the system. If a device is shipped
|
||||
// with such a backward incompatible change, it has a high risk of breaking
|
||||
// later when a module using the interface is updated, e.g., Mainline modules.
|
||||
|
||||
package android.hardware.vibrator;
|
||||
@VintfStability
|
||||
parcelable PwleV2OutputMapEntry {
|
||||
float frequencyHz;
|
||||
float maxOutputAccelerationGs;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
|
||||
// two cases:
|
||||
// 1). this is a frozen version file - do not edit this in any case.
|
||||
// 2). this is a 'current' file. If you make a backwards compatible change to
|
||||
// the interface (from the latest frozen version), the build system will
|
||||
// prompt you to update this file with `m <name>-update-api`.
|
||||
//
|
||||
// You must not make a backward incompatible change to any AIDL file built
|
||||
// with the aidl_interface module type with versions property set. The module
|
||||
// type is used to build AIDL files in a way that they can be used across
|
||||
// independently updatable components of the system. If a device is shipped
|
||||
// with such a backward incompatible change, it has a high risk of breaking
|
||||
// later when a module using the interface is updated, e.g., Mainline modules.
|
||||
|
||||
package android.hardware.vibrator;
|
||||
@VintfStability
|
||||
parcelable PwleV2Primitive {
|
||||
float amplitude;
|
||||
float frequencyHz;
|
||||
int timeMillis;
|
||||
}
|
||||
@@ -23,6 +23,8 @@ import android.hardware.vibrator.Effect;
|
||||
import android.hardware.vibrator.EffectStrength;
|
||||
import android.hardware.vibrator.IVibratorCallback;
|
||||
import android.hardware.vibrator.PrimitivePwle;
|
||||
import android.hardware.vibrator.PwleV2OutputMapEntry;
|
||||
import android.hardware.vibrator.PwleV2Primitive;
|
||||
import android.hardware.vibrator.VendorEffect;
|
||||
|
||||
@VintfStability
|
||||
@@ -75,6 +77,10 @@ interface IVibrator {
|
||||
* Whether perform w/ vendor effect is supported.
|
||||
*/
|
||||
const int CAP_PERFORM_VENDOR_EFFECTS = 1 << 11;
|
||||
/**
|
||||
* Whether composePwleV2 for PwlePrimitives is supported.
|
||||
*/
|
||||
const int CAP_COMPOSE_PWLE_EFFECTS_V2 = 1 << 12;
|
||||
|
||||
/**
|
||||
* Determine capabilities of the vibrator HAL (CAP_* mask)
|
||||
@@ -385,4 +391,82 @@ interface IVibrator {
|
||||
* - EX_SERVICE_SPECIFIC for bad vendor data, vibration is not triggered.
|
||||
*/
|
||||
void performVendorEffect(in VendorEffect vendorEffect, in IVibratorCallback callback);
|
||||
|
||||
/**
|
||||
* Retrieves a mapping of vibration frequency (Hz) to the maximum achievable output
|
||||
* acceleration (Gs) the device can reach at that frequency.
|
||||
*
|
||||
* The map, represented as a list of `PwleV2OutputMapEntry` (frequency, output acceleration)
|
||||
* pairs, defines the device's frequency response. The platform uses the minimum and maximum
|
||||
* frequency values to determine the supported input range for `IVibrator.composePwleV2`.
|
||||
* Output acceleration values are used to identify a frequency range suitable to safely play
|
||||
* perceivable vibrations with a simple API. The map is also exposed for developers using an
|
||||
* advanced API.
|
||||
*
|
||||
* The platform does not impose specific requirements on map resolution which can vary
|
||||
* depending on the shape of device output curve. The values will be linearly interpolated
|
||||
* during lookups. The platform will provide a simple API, defined by the first frequency range
|
||||
* where output acceleration consistently exceeds a minimum threshold of 10 db SL.
|
||||
*
|
||||
*
|
||||
* This may not be supported and this support is reflected in getCapabilities
|
||||
* (CAP_COMPOSE_PWLE_EFFECTS_V2). If this is supported, it's expected to be non-empty and
|
||||
* describe a valid non-empty frequency range where the simple API can be defined
|
||||
* (i.e. a range where the output acceleration is always above 10 db SL).
|
||||
*
|
||||
* @return A list of map entries representing the frequency to max acceleration
|
||||
* mapping.
|
||||
* @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities.
|
||||
*/
|
||||
List<PwleV2OutputMapEntry> getPwleV2FrequencyToOutputAccelerationMap();
|
||||
|
||||
/**
|
||||
* Retrieve the maximum duration allowed for any primitive PWLE in units of
|
||||
* milliseconds.
|
||||
*
|
||||
* This may not be supported and this support is reflected in
|
||||
* getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2).
|
||||
*
|
||||
* @return The maximum duration allowed for a single PrimitivePwle. Non-zero value if supported.
|
||||
* @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities.
|
||||
*/
|
||||
int getPwleV2PrimitiveDurationMaxMillis();
|
||||
|
||||
/**
|
||||
* Retrieve the maximum number of PWLE primitives input supported by IVibrator.composePwleV2.
|
||||
*
|
||||
* This may not be supported and this support is reflected in
|
||||
* getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2). Devices supporting PWLE effects must
|
||||
* support effects with at least 16 PwleV2Primitive.
|
||||
*
|
||||
* @return The maximum count allowed. Non-zero value if supported.
|
||||
* @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities.
|
||||
*/
|
||||
int getPwleV2CompositionSizeMax();
|
||||
|
||||
/**
|
||||
* Retrieves the minimum duration (in milliseconds) of any segment within a
|
||||
* PWLE effect. Devices supporting PWLE effects must support a minimum ramp
|
||||
* time of 20 milliseconds.
|
||||
*
|
||||
* This may not be supported and this support is reflected in
|
||||
* getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2).
|
||||
*
|
||||
* @return The minimum duration allowed for a single PrimitivePwle. Non-zero value if supported.
|
||||
* @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities.
|
||||
*/
|
||||
int getPwleV2PrimitiveDurationMinMillis();
|
||||
|
||||
/**
|
||||
* Play composed sequence of chirps with optional callback upon completion.
|
||||
*
|
||||
* This may not be supported and this support is reflected in
|
||||
* getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2).
|
||||
*
|
||||
* Doing this operation while the vibrator is already on is undefined behavior. Clients should
|
||||
* explicitly call off. IVibratorCallback.onComplete() support is required for this API.
|
||||
*
|
||||
* @param composite An array of primitives that represents a PWLE (Piecewise-Linear Envelope).
|
||||
*/
|
||||
void composePwleV2(in PwleV2Primitive[] composite, in IVibratorCallback callback);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.
|
||||
*/
|
||||
|
||||
package android.hardware.vibrator;
|
||||
|
||||
@VintfStability
|
||||
parcelable PwleV2OutputMapEntry {
|
||||
/**
|
||||
* Absolute frequency point in the units of hertz
|
||||
*
|
||||
*/
|
||||
float frequencyHz;
|
||||
|
||||
/**
|
||||
* Max output acceleration for the specified frequency in units of Gs.
|
||||
*
|
||||
* This value represents the maximum safe output acceleration (in Gs) achievable at the
|
||||
* specified frequency, typically determined during calibration. The actual output acceleration
|
||||
* is assumed to scale linearly with the input amplitude within the range of [0, 1].
|
||||
*/
|
||||
float maxOutputAccelerationGs;
|
||||
}
|
||||
45
vibrator/aidl/android/hardware/vibrator/PwleV2Primitive.aidl
Normal file
45
vibrator/aidl/android/hardware/vibrator/PwleV2Primitive.aidl
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.
|
||||
*/
|
||||
|
||||
package android.hardware.vibrator;
|
||||
|
||||
@VintfStability
|
||||
parcelable PwleV2Primitive {
|
||||
/**
|
||||
* Input amplitude ranges from 0.0 (inclusive) to 1.0 (inclusive), representing the relative
|
||||
* input value. Actual output acceleration depends on frequency and device response curve
|
||||
* (see IVibrator.getPwleV2FrequencyToOutputAccelerationMap for max values).
|
||||
*
|
||||
* Input amplitude linearly maps to output acceleration (e.g., 0.5 amplitude yields half the
|
||||
* max acceleration for that frequency).
|
||||
*
|
||||
* 0.0 represents no output acceleration amplitude
|
||||
* 1.0 represents the maximum achievable strength for each frequency, as determined by the
|
||||
* actuator response curve
|
||||
*/
|
||||
float amplitude;
|
||||
|
||||
/**
|
||||
* Absolute frequency point in the units of hertz
|
||||
*
|
||||
* Values are within the continuous inclusive frequency range defined by
|
||||
* IVibrator#getPwleV2FrequencyToOutputAccelerationMap.
|
||||
*/
|
||||
float frequencyHz;
|
||||
|
||||
/* Total time from the previous PWLE point to the current one in units of milliseconds. */
|
||||
int timeMillis;
|
||||
}
|
||||
@@ -27,9 +27,12 @@ namespace vibrator {
|
||||
static constexpr int32_t COMPOSE_DELAY_MAX_MS = 1000;
|
||||
static constexpr int32_t COMPOSE_SIZE_MAX = 256;
|
||||
static constexpr int32_t COMPOSE_PWLE_SIZE_MAX = 127;
|
||||
static constexpr int32_t COMPOSE_PWLE_V2_SIZE_MAX = 16;
|
||||
|
||||
static constexpr float Q_FACTOR = 11.0;
|
||||
static constexpr int32_t COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS = 16383;
|
||||
static constexpr int32_t COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MAX_MS = 1000;
|
||||
static constexpr int32_t COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MIN_MS = 20;
|
||||
static constexpr float PWLE_LEVEL_MIN = 0.0;
|
||||
static constexpr float PWLE_LEVEL_MAX = 1.0;
|
||||
static constexpr float PWLE_FREQUENCY_RESOLUTION_HZ = 1.0;
|
||||
@@ -44,12 +47,25 @@ static constexpr int32_t ERROR_CODE_INVALID_DURATION = 1;
|
||||
|
||||
ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
|
||||
LOG(VERBOSE) << "Vibrator reporting capabilities";
|
||||
*_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
|
||||
IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
|
||||
IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS |
|
||||
IVibrator::CAP_ALWAYS_ON_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY |
|
||||
IVibrator::CAP_GET_Q_FACTOR | IVibrator::CAP_FREQUENCY_CONTROL |
|
||||
IVibrator::CAP_COMPOSE_PWLE_EFFECTS | IVibrator::CAP_PERFORM_VENDOR_EFFECTS;
|
||||
std::lock_guard lock(mMutex);
|
||||
if (mCapabilities == 0) {
|
||||
if (!getInterfaceVersion(&mVersion).isOk()) {
|
||||
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
|
||||
}
|
||||
mCapabilities = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
|
||||
IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
|
||||
IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS |
|
||||
IVibrator::CAP_ALWAYS_ON_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY |
|
||||
IVibrator::CAP_GET_Q_FACTOR | IVibrator::CAP_FREQUENCY_CONTROL |
|
||||
IVibrator::CAP_COMPOSE_PWLE_EFFECTS;
|
||||
|
||||
if (mVersion >= 3) {
|
||||
mCapabilities |= (IVibrator::CAP_PERFORM_VENDOR_EFFECTS |
|
||||
IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2);
|
||||
}
|
||||
}
|
||||
|
||||
*_aidl_return = mCapabilities;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
@@ -108,6 +124,13 @@ ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
|
||||
ndk::ScopedAStatus Vibrator::performVendorEffect(
|
||||
const VendorEffect& effect, const std::shared_ptr<IVibratorCallback>& callback) {
|
||||
LOG(VERBOSE) << "Vibrator perform vendor effect";
|
||||
int32_t capabilities = 0;
|
||||
if (!getCapabilities(&capabilities).isOk()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) {
|
||||
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
|
||||
}
|
||||
EffectStrength strength = effect.strength;
|
||||
if (strength != EffectStrength::LIGHT && strength != EffectStrength::MEDIUM &&
|
||||
strength != EffectStrength::STRONG) {
|
||||
@@ -449,6 +472,114 @@ ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &compo
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Vibrator::getPwleV2FrequencyToOutputAccelerationMap(
|
||||
std::vector<PwleV2OutputMapEntry>* _aidl_return) {
|
||||
std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
|
||||
|
||||
std::vector<std::pair<float, float>> frequencyToOutputAccelerationData = {
|
||||
{30.0f, 0.01f}, {46.0f, 0.09f}, {50.0f, 0.1f}, {55.0f, 0.12f}, {62.0f, 0.66f},
|
||||
{83.0f, 0.82f}, {85.0f, 0.85f}, {92.0f, 1.05f}, {107.0f, 1.63f}, {115.0f, 1.72f},
|
||||
{123.0f, 1.81f}, {135.0f, 2.23f}, {144.0f, 2.47f}, {145.0f, 2.5f}, {150.0f, 3.0f},
|
||||
{175.0f, 2.51f}, {181.0f, 2.41f}, {190.0f, 2.28f}, {200.0f, 2.08f}, {204.0f, 1.96f},
|
||||
{205.0f, 1.9f}, {224.0f, 1.7f}, {235.0f, 1.5f}, {242.0f, 1.46f}, {253.0f, 1.41f},
|
||||
{263.0f, 1.39f}, {65.0f, 1.38f}, {278.0f, 1.37f}, {294.0f, 1.35f}, {300.0f, 1.34f}};
|
||||
for (const auto& entry : frequencyToOutputAccelerationData) {
|
||||
frequencyToOutputAccelerationMap.push_back(
|
||||
PwleV2OutputMapEntry(/*frequency=*/entry.first,
|
||||
/*maxOutputAcceleration=*/entry.second));
|
||||
}
|
||||
|
||||
*_aidl_return = frequencyToOutputAccelerationMap;
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Vibrator::getPwleV2PrimitiveDurationMaxMillis(int32_t* maxDurationMs) {
|
||||
*maxDurationMs = COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MAX_MS;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Vibrator::getPwleV2CompositionSizeMax(int32_t* maxSize) {
|
||||
*maxSize = COMPOSE_PWLE_V2_SIZE_MAX;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Vibrator::getPwleV2PrimitiveDurationMinMillis(int32_t* minDurationMs) {
|
||||
*minDurationMs = COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MIN_MS;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
float getPwleV2FrequencyMinHz(std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap) {
|
||||
if (frequencyToOutputAccelerationMap.empty()) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float minFrequency = frequencyToOutputAccelerationMap[0].frequencyHz;
|
||||
|
||||
for (const auto& entry : frequencyToOutputAccelerationMap) {
|
||||
if (entry.frequencyHz < minFrequency) {
|
||||
minFrequency = entry.frequencyHz;
|
||||
}
|
||||
}
|
||||
|
||||
return minFrequency;
|
||||
}
|
||||
|
||||
float getPwleV2FrequencyMaxHz(std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap) {
|
||||
if (frequencyToOutputAccelerationMap.empty()) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float maxFrequency = frequencyToOutputAccelerationMap[0].frequencyHz;
|
||||
|
||||
for (const auto& entry : frequencyToOutputAccelerationMap) {
|
||||
if (entry.frequencyHz > maxFrequency) {
|
||||
maxFrequency = entry.frequencyHz;
|
||||
}
|
||||
}
|
||||
|
||||
return maxFrequency;
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Vibrator::composePwleV2(const std::vector<PwleV2Primitive>& composite,
|
||||
const std::shared_ptr<IVibratorCallback>& callback) {
|
||||
int compositionSizeMax;
|
||||
getPwleV2CompositionSizeMax(&compositionSizeMax);
|
||||
if (composite.size() <= 0 || composite.size() > compositionSizeMax) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
|
||||
int32_t totalEffectDuration = 0;
|
||||
std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
|
||||
getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap);
|
||||
float minFrequency = getPwleV2FrequencyMinHz(frequencyToOutputAccelerationMap);
|
||||
float maxFrequency = getPwleV2FrequencyMaxHz(frequencyToOutputAccelerationMap);
|
||||
|
||||
for (auto& e : composite) {
|
||||
if (e.timeMillis < 0.0f || e.timeMillis > COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MAX_MS) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
if (e.amplitude < 0.0f || e.amplitude > 1.0f) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
if (e.frequencyHz < minFrequency || e.frequencyHz > maxFrequency) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
totalEffectDuration += e.timeMillis;
|
||||
}
|
||||
|
||||
std::thread([totalEffectDuration, callback] {
|
||||
LOG(VERBOSE) << "Starting composePwleV2 on another thread";
|
||||
usleep(totalEffectDuration * 1000);
|
||||
if (callback != nullptr) {
|
||||
LOG(VERBOSE) << "Notifying compose PWLE V2 complete";
|
||||
callback->onComplete();
|
||||
}
|
||||
}).detach();
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
} // namespace vibrator
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/vibrator/BnVibrator.h>
|
||||
#include <android-base/thread_annotations.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
@@ -57,7 +58,18 @@ class Vibrator : public BnVibrator {
|
||||
ndk::ScopedAStatus getSupportedBraking(std::vector<Braking>* supported) override;
|
||||
ndk::ScopedAStatus composePwle(const std::vector<PrimitivePwle> &composite,
|
||||
const std::shared_ptr<IVibratorCallback> &callback) override;
|
||||
ndk::ScopedAStatus getPwleV2FrequencyToOutputAccelerationMap(
|
||||
std::vector<PwleV2OutputMapEntry>* _aidl_return) override;
|
||||
ndk::ScopedAStatus getPwleV2PrimitiveDurationMaxMillis(int32_t* maxDurationMs) override;
|
||||
ndk::ScopedAStatus getPwleV2PrimitiveDurationMinMillis(int32_t* minDurationMs) override;
|
||||
ndk::ScopedAStatus getPwleV2CompositionSizeMax(int32_t* maxSize) override;
|
||||
ndk::ScopedAStatus composePwleV2(const std::vector<PwleV2Primitive>& composite,
|
||||
const std::shared_ptr<IVibratorCallback>& callback) override;
|
||||
|
||||
private:
|
||||
mutable std::mutex mMutex;
|
||||
int32_t mVersion GUARDED_BY(mMutex) = 0; // current Hal version
|
||||
int32_t mCapabilities GUARDED_BY(mMutex) = 0;
|
||||
};
|
||||
|
||||
} // namespace vibrator
|
||||
|
||||
@@ -27,8 +27,12 @@
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <future>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
#include "persistable_bundle_utils.h"
|
||||
#include "pwle_v2_utils.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
using aidl::android::hardware::vibrator::ActivePwle;
|
||||
@@ -42,12 +46,16 @@ using aidl::android::hardware::vibrator::EffectStrength;
|
||||
using aidl::android::hardware::vibrator::IVibrator;
|
||||
using aidl::android::hardware::vibrator::IVibratorManager;
|
||||
using aidl::android::hardware::vibrator::PrimitivePwle;
|
||||
using aidl::android::hardware::vibrator::PwleV2OutputMapEntry;
|
||||
using aidl::android::hardware::vibrator::PwleV2Primitive;
|
||||
using aidl::android::hardware::vibrator::VendorEffect;
|
||||
using aidl::android::os::PersistableBundle;
|
||||
using std::chrono::high_resolution_clock;
|
||||
|
||||
using namespace ::std::chrono_literals;
|
||||
|
||||
namespace pwle_v2_utils = aidl::android::hardware::vibrator::testing::pwlev2;
|
||||
|
||||
const std::vector<Effect> kEffects{ndk::enum_range<Effect>().begin(),
|
||||
ndk::enum_range<Effect>().end()};
|
||||
const std::vector<EffectStrength> kEffectStrengths{ndk::enum_range<EffectStrength>().begin(),
|
||||
@@ -80,6 +88,8 @@ const std::vector<CompositePrimitive> kInvalidPrimitives = {
|
||||
// Timeout to wait for vibration callback completion.
|
||||
static constexpr std::chrono::milliseconds VIBRATION_CALLBACK_TIMEOUT = 100ms;
|
||||
|
||||
static constexpr int32_t VENDOR_EFFECTS_MIN_VERSION = 3;
|
||||
|
||||
static std::vector<std::string> findVibratorManagerNames() {
|
||||
std::vector<std::string> names;
|
||||
constexpr auto callback = [](const char* instance, void* context) {
|
||||
@@ -137,6 +147,7 @@ class VibratorAidl : public testing::TestWithParam<std::tuple<int32_t, int32_t>>
|
||||
}
|
||||
|
||||
ASSERT_NE(vibrator, nullptr);
|
||||
EXPECT_OK(vibrator->getInterfaceVersion(&version));
|
||||
EXPECT_OK(vibrator->getCapabilities(&capabilities));
|
||||
}
|
||||
|
||||
@@ -146,6 +157,7 @@ class VibratorAidl : public testing::TestWithParam<std::tuple<int32_t, int32_t>>
|
||||
}
|
||||
|
||||
std::shared_ptr<IVibrator> vibrator;
|
||||
int32_t version;
|
||||
int32_t capabilities;
|
||||
};
|
||||
|
||||
@@ -476,6 +488,10 @@ TEST_P(VibratorAidl, PerformVendorEffectInvalidScale) {
|
||||
}
|
||||
|
||||
TEST_P(VibratorAidl, PerformVendorEffectUnsupported) {
|
||||
if (version < VENDOR_EFFECTS_MIN_VERSION) {
|
||||
EXPECT_EQ(capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS, 0)
|
||||
<< "Vibrator version " << version << " should not report vendor effects capability";
|
||||
}
|
||||
if (capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) return;
|
||||
|
||||
for (EffectStrength strength : kEffectStrengths) {
|
||||
@@ -1035,6 +1051,156 @@ TEST_P(VibratorAidl, ComposePwleSegmentDurationBoundary) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(VibratorAidl, PwleV2FrequencyToOutputAccelerationMapHasValidFrequencyRange) {
|
||||
std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
|
||||
ndk::ScopedAStatus status =
|
||||
vibrator->getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap);
|
||||
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) {
|
||||
EXPECT_OK(std::move(status));
|
||||
ASSERT_FALSE(frequencyToOutputAccelerationMap.empty());
|
||||
auto sharpnessRange =
|
||||
pwle_v2_utils::getPwleV2SharpnessRange(vibrator, frequencyToOutputAccelerationMap);
|
||||
// Validate the curve provides a usable sharpness range, which is a range of frequencies
|
||||
// that are supported by the device.
|
||||
ASSERT_TRUE(sharpnessRange.first >= 0);
|
||||
// Validate that the sharpness range is a valid interval, not a single point.
|
||||
ASSERT_TRUE(sharpnessRange.first < sharpnessRange.second);
|
||||
} else {
|
||||
EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(VibratorAidl, GetPwleV2PrimitiveDurationMaxMillis) {
|
||||
int32_t durationMs;
|
||||
ndk::ScopedAStatus status = vibrator->getPwleV2PrimitiveDurationMaxMillis(&durationMs);
|
||||
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) {
|
||||
EXPECT_OK(std::move(status));
|
||||
ASSERT_GT(durationMs, 0); // Ensure greater than zero
|
||||
ASSERT_GE(durationMs,
|
||||
pwle_v2_utils::COMPOSE_PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS);
|
||||
} else {
|
||||
EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(VibratorAidl, GetPwleV2CompositionSizeMax) {
|
||||
int32_t maxSize;
|
||||
ndk::ScopedAStatus status = vibrator->getPwleV2CompositionSizeMax(&maxSize);
|
||||
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) {
|
||||
EXPECT_OK(std::move(status));
|
||||
ASSERT_GT(maxSize, 0); // Ensure greater than zero
|
||||
ASSERT_GE(maxSize, pwle_v2_utils::COMPOSE_PWLE_V2_MIN_REQUIRED_SIZE);
|
||||
} else {
|
||||
EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(VibratorAidl, GetPwleV2PrimitiveDurationMinMillis) {
|
||||
int32_t durationMs;
|
||||
ndk::ScopedAStatus status = vibrator->getPwleV2PrimitiveDurationMinMillis(&durationMs);
|
||||
if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) {
|
||||
EXPECT_OK(std::move(status));
|
||||
ASSERT_GT(durationMs, 0); // Ensure greater than zero
|
||||
ASSERT_LE(durationMs, pwle_v2_utils::COMPOSE_PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS);
|
||||
} else {
|
||||
EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(VibratorAidl, ComposeValidPwleV2Effect) {
|
||||
if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
|
||||
GTEST_SKIP() << "PWLE V2 not supported, skipping test";
|
||||
return;
|
||||
}
|
||||
|
||||
EXPECT_OK(vibrator->composePwleV2(pwle_v2_utils::composeValidPwleV2Effect(vibrator), nullptr));
|
||||
EXPECT_OK(vibrator->off());
|
||||
}
|
||||
|
||||
TEST_P(VibratorAidl, ComposeValidPwleV2EffectWithCallback) {
|
||||
if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
|
||||
GTEST_SKIP() << "PWLE V2 not supported, skipping test";
|
||||
return;
|
||||
}
|
||||
|
||||
std::promise<void> completionPromise;
|
||||
std::future<void> completionFuture{completionPromise.get_future()};
|
||||
auto callback = ndk::SharedRefBase::make<CompletionCallback>(
|
||||
[&completionPromise] { completionPromise.set_value(); });
|
||||
|
||||
int32_t minDuration;
|
||||
EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDuration));
|
||||
auto timeout = std::chrono::milliseconds(minDuration) + VIBRATION_CALLBACK_TIMEOUT;
|
||||
float minFrequency = pwle_v2_utils::getPwleV2FrequencyMinHz(vibrator);
|
||||
|
||||
EXPECT_OK(vibrator->composePwleV2(
|
||||
{PwleV2Primitive(/*amplitude=*/0.5, minFrequency, minDuration)}, callback));
|
||||
EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
|
||||
EXPECT_OK(vibrator->off());
|
||||
}
|
||||
|
||||
TEST_P(VibratorAidl, composePwleV2EffectWithTooManyPoints) {
|
||||
if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
|
||||
GTEST_SKIP() << "PWLE V2 not supported, skipping test";
|
||||
return;
|
||||
}
|
||||
|
||||
EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(
|
||||
pwle_v2_utils::composePwleV2EffectWithTooManyPoints(vibrator), nullptr));
|
||||
}
|
||||
|
||||
TEST_P(VibratorAidl, composeInvalidPwleV2Effect) {
|
||||
if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) {
|
||||
GTEST_SKIP() << "PWLE V2 not supported, skipping test";
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve min and max durations
|
||||
int32_t minDurationMs, maxDurationMs;
|
||||
EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDurationMs));
|
||||
EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMaxMillis(&maxDurationMs));
|
||||
|
||||
std::vector<PwleV2Primitive> composePwle;
|
||||
|
||||
// Negative amplitude
|
||||
composePwle.push_back(PwleV2Primitive(/*amplitude=*/-0.8f, /*frequency=*/100, minDurationMs));
|
||||
EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
|
||||
<< "Composing PWLE V2 effect with negative amplitude should fail";
|
||||
composePwle.clear();
|
||||
|
||||
// Amplitude exceeding 1.0
|
||||
composePwle.push_back(PwleV2Primitive(/*amplitude=*/1.2f, /*frequency=*/100, minDurationMs));
|
||||
EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
|
||||
<< "Composing PWLE V2 effect with amplitude greater than 1.0 should fail";
|
||||
composePwle.clear();
|
||||
|
||||
// Duration exceeding maximum
|
||||
composePwle.push_back(
|
||||
PwleV2Primitive(/*amplitude=*/0.2f, /*frequency=*/100, maxDurationMs + 10));
|
||||
EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
|
||||
<< "Composing PWLE V2 effect with duration exceeding maximum should fail";
|
||||
composePwle.clear();
|
||||
|
||||
// Negative duration
|
||||
composePwle.push_back(PwleV2Primitive(/*amplitude=*/0.2f, /*frequency=*/100, /*time=*/-1));
|
||||
EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
|
||||
<< "Composing PWLE V2 effect with negative duration should fail";
|
||||
composePwle.clear();
|
||||
|
||||
// Frequency below minimum
|
||||
float minFrequency = pwle_v2_utils::getPwleV2FrequencyMinHz(vibrator);
|
||||
composePwle.push_back(PwleV2Primitive(/*amplitude=*/0.2f, minFrequency - 1, minDurationMs));
|
||||
EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
|
||||
<< "Composing PWLE V2 effect with frequency below minimum should fail";
|
||||
composePwle.clear();
|
||||
|
||||
// Frequency above maximum
|
||||
float maxFrequency = pwle_v2_utils::getPwleV2FrequencyMaxHz(vibrator);
|
||||
composePwle.push_back(PwleV2Primitive(/*amplitude=*/0.2f, maxFrequency + 1, minDurationMs));
|
||||
EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr))
|
||||
<< "Composing PWLE V2 effect with frequency above maximum should fail";
|
||||
}
|
||||
|
||||
std::vector<std::tuple<int32_t, int32_t>> GenerateVibratorMapping() {
|
||||
std::vector<std::tuple<int32_t, int32_t>> tuples;
|
||||
|
||||
|
||||
219
vibrator/aidl/vts/pwle_v2_utils.h
Normal file
219
vibrator/aidl/vts/pwle_v2_utils.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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 VIBRATOR_HAL_PWLE_V2_UTILS_H
|
||||
#define VIBRATOR_HAL_PWLE_V2_UTILS_H
|
||||
|
||||
#include <aidl/android/hardware/vibrator/IVibrator.h>
|
||||
#include "test_utils.h"
|
||||
|
||||
using aidl::android::hardware::vibrator::IVibrator;
|
||||
using aidl::android::hardware::vibrator::PwleV2OutputMapEntry;
|
||||
using aidl::android::hardware::vibrator::PwleV2Primitive;
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace vibrator {
|
||||
namespace testing {
|
||||
namespace pwlev2 {
|
||||
|
||||
static constexpr int32_t COMPOSE_PWLE_V2_MIN_REQUIRED_SIZE = 16;
|
||||
static constexpr int32_t COMPOSE_PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS = 1000;
|
||||
static constexpr int32_t COMPOSE_PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS = 20;
|
||||
static constexpr int32_t COMPOSE_PWLE_V2_MIN_REQUIRED_SENSITIVITY_DB_SL = 10;
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* Returns a vector of (frequency in Hz, acceleration in dB) pairs, where the acceleration
|
||||
* value denotes the minimum output required at the corresponding frequency to be perceptible
|
||||
* by a human.
|
||||
*/
|
||||
static std::vector<std::pair<float, float>> getMinPerceptibleLevel() {
|
||||
return {{0.4f, -97.81f}, {2.0f, -69.86f}, {3.0f, -62.81f}, {4.0f, -58.81f},
|
||||
{5.0f, -56.69f}, {6.0f, -54.77f}, {7.2f, -52.85f}, {8.0f, -51.77f},
|
||||
{8.64f, -50.84f}, {10.0f, -48.90f}, {10.37f, -48.52f}, {12.44f, -46.50f},
|
||||
{14.93f, -44.43f}, {15.0f, -44.35f}, {17.92f, -41.96f}, {20.0f, -40.36f},
|
||||
{21.5f, -39.60f}, {25.0f, -37.48f}, {25.8f, -36.93f}, {30.0f, -34.31f},
|
||||
{35.0f, -33.13f}, {40.0f, -32.81f}, {50.0f, -31.94f}, {60.0f, -31.77f},
|
||||
{70.0f, -31.59f}, {72.0f, -31.55f}, {80.0f, -31.77f}, {86.4f, -31.94f},
|
||||
{90.0f, -31.73f}, {100.0f, -31.90f}, {103.68f, -31.77f}, {124.42f, -31.70f},
|
||||
{149.3f, -31.38f}, {150.0f, -31.35f}, {179.16f, -31.02f}, {200.0f, -30.86f},
|
||||
{215.0f, -30.35f}, {250.0f, -28.98f}, {258.0f, -28.68f}, {300.0f, -26.81f},
|
||||
{400.0f, -19.81f}};
|
||||
}
|
||||
|
||||
static float interpolateLinearly(const std::vector<float>& xAxis, const std::vector<float>& yAxis,
|
||||
float x) {
|
||||
EXPECT_TRUE(!xAxis.empty());
|
||||
EXPECT_TRUE(xAxis.size() == yAxis.size());
|
||||
|
||||
if (x <= xAxis.front()) return yAxis.front();
|
||||
if (x >= xAxis.back()) return yAxis.back();
|
||||
|
||||
auto it = std::upper_bound(xAxis.begin(), xAxis.end(), x);
|
||||
int i = std::distance(xAxis.begin(), it) - 1; // Index of the lower bound
|
||||
|
||||
const float& x0 = xAxis[i];
|
||||
const float& y0 = yAxis[i];
|
||||
const float& x1 = xAxis[i + 1];
|
||||
const float& y1 = yAxis[i + 1];
|
||||
|
||||
return y0 + (x - x0) * (y1 - y0) / (x1 - x0);
|
||||
}
|
||||
|
||||
static float minPerceptibleDbCurve(float frequency) {
|
||||
// Initialize minPerceptibleMap only once
|
||||
static auto minPerceptibleMap = []() -> std::function<float(float)> {
|
||||
static std::vector<float> minPerceptibleFrequencies;
|
||||
static std::vector<float> minPerceptibleAccelerations;
|
||||
|
||||
auto minPerceptibleLevel = getMinPerceptibleLevel();
|
||||
// Sort the 'minPerceptibleLevel' data in ascending order based on the
|
||||
// frequency values (first element of each pair).
|
||||
std::sort(minPerceptibleLevel.begin(), minPerceptibleLevel.end(),
|
||||
[](const auto& a, const auto& b) { return a.first < b.first; });
|
||||
|
||||
for (const auto& entry : minPerceptibleLevel) {
|
||||
minPerceptibleFrequencies.push_back(entry.first);
|
||||
minPerceptibleAccelerations.push_back(entry.second);
|
||||
}
|
||||
|
||||
return [&](float freq) {
|
||||
return interpolateLinearly(minPerceptibleFrequencies, minPerceptibleAccelerations,
|
||||
freq);
|
||||
};
|
||||
}();
|
||||
|
||||
return minPerceptibleMap(frequency);
|
||||
}
|
||||
|
||||
static float convertSensitivityLevelToDecibel(int sl, float frequency) {
|
||||
return sl + minPerceptibleDbCurve(frequency);
|
||||
}
|
||||
|
||||
static float convertDecibelToAcceleration(float db) {
|
||||
return std::pow(10.0f, db / 20.0f);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
static float convertSensitivityLevelToAcceleration(int sl, float frequency) {
|
||||
return pwlev2::convertDecibelToAcceleration(
|
||||
pwlev2::convertSensitivityLevelToDecibel(sl, frequency));
|
||||
}
|
||||
|
||||
static float getPwleV2FrequencyMinHz(const std::shared_ptr<IVibrator>& vibrator) {
|
||||
std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
|
||||
EXPECT_OK(
|
||||
vibrator->getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap));
|
||||
EXPECT_TRUE(!frequencyToOutputAccelerationMap.empty());
|
||||
|
||||
auto entry = std::min_element(
|
||||
frequencyToOutputAccelerationMap.begin(), frequencyToOutputAccelerationMap.end(),
|
||||
[](const auto& a, const auto& b) { return a.frequencyHz < b.frequencyHz; });
|
||||
|
||||
return entry->frequencyHz;
|
||||
}
|
||||
|
||||
static float getPwleV2FrequencyMaxHz(const std::shared_ptr<IVibrator>& vibrator) {
|
||||
std::vector<PwleV2OutputMapEntry> frequencyToOutputAccelerationMap;
|
||||
EXPECT_OK(
|
||||
vibrator->getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap));
|
||||
EXPECT_TRUE(!frequencyToOutputAccelerationMap.empty());
|
||||
|
||||
auto entry = std::max_element(
|
||||
frequencyToOutputAccelerationMap.begin(), frequencyToOutputAccelerationMap.end(),
|
||||
[](const auto& a, const auto& b) { return a.frequencyHz < b.frequencyHz; });
|
||||
|
||||
return entry->frequencyHz;
|
||||
}
|
||||
|
||||
static std::vector<PwleV2Primitive> composeValidPwleV2Effect(
|
||||
const std::shared_ptr<IVibrator>& vibrator) {
|
||||
int32_t minDurationMs;
|
||||
EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDurationMs));
|
||||
int32_t maxDurationMs;
|
||||
EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMaxMillis(&maxDurationMs));
|
||||
float minFrequency = getPwleV2FrequencyMinHz(vibrator);
|
||||
float maxFrequency = getPwleV2FrequencyMaxHz(vibrator);
|
||||
int32_t maxCompositionSize;
|
||||
EXPECT_OK(vibrator->getPwleV2CompositionSizeMax(&maxCompositionSize));
|
||||
|
||||
std::vector<PwleV2Primitive> pwleEffect;
|
||||
|
||||
pwleEffect.emplace_back(0.1f, minFrequency, minDurationMs);
|
||||
pwleEffect.emplace_back(0.5f, maxFrequency, maxDurationMs);
|
||||
|
||||
float variedFrequency = (minFrequency + maxFrequency) / 2.0f;
|
||||
for (int i = 0; i < maxCompositionSize - 2; i++) {
|
||||
pwleEffect.emplace_back(0.7f, variedFrequency, minDurationMs);
|
||||
}
|
||||
|
||||
return pwleEffect;
|
||||
}
|
||||
|
||||
static std::vector<PwleV2Primitive> composePwleV2EffectWithTooManyPoints(
|
||||
const std::shared_ptr<IVibrator>& vibrator) {
|
||||
int32_t minDurationMs, maxCompositionSize;
|
||||
EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDurationMs));
|
||||
EXPECT_OK(vibrator->getPwleV2CompositionSizeMax(&maxCompositionSize));
|
||||
float maxFrequency = getPwleV2FrequencyMaxHz(vibrator);
|
||||
|
||||
std::vector<PwleV2Primitive> pwleEffect(maxCompositionSize + 1); // +1 to exceed the limit
|
||||
|
||||
std::fill(pwleEffect.begin(), pwleEffect.end(),
|
||||
PwleV2Primitive(/*amplitude=*/0.2f, maxFrequency, minDurationMs));
|
||||
|
||||
return pwleEffect;
|
||||
}
|
||||
|
||||
static std::pair<float, float> getPwleV2SharpnessRange(
|
||||
const std::shared_ptr<IVibrator>& vibrator,
|
||||
std::vector<PwleV2OutputMapEntry> freqToOutputAccelerationMap) {
|
||||
std::pair<float, float> sharpnessRange = {-1, -1};
|
||||
|
||||
// Sort the entries by frequency in ascending order
|
||||
std::sort(freqToOutputAccelerationMap.begin(), freqToOutputAccelerationMap.end(),
|
||||
[](const auto& a, const auto& b) { return a.frequencyHz < b.frequencyHz; });
|
||||
|
||||
for (const auto& entry : freqToOutputAccelerationMap) {
|
||||
float minAcceptableOutputAcceleration = convertSensitivityLevelToAcceleration(
|
||||
pwlev2::COMPOSE_PWLE_V2_MIN_REQUIRED_SENSITIVITY_DB_SL, entry.frequencyHz);
|
||||
|
||||
if (sharpnessRange.first < 0 &&
|
||||
minAcceptableOutputAcceleration <= entry.maxOutputAccelerationGs) {
|
||||
sharpnessRange.first = entry.frequencyHz; // Found the lower bound
|
||||
} else if (sharpnessRange.first >= 0 &&
|
||||
minAcceptableOutputAcceleration >= entry.maxOutputAccelerationGs) {
|
||||
sharpnessRange.second = entry.frequencyHz; // Found the upper bound
|
||||
return sharpnessRange;
|
||||
}
|
||||
}
|
||||
|
||||
if (sharpnessRange.first >= 0) {
|
||||
// If only the lower bound was found, set the upper bound to the max frequency.
|
||||
sharpnessRange.second = getPwleV2FrequencyMaxHz(vibrator);
|
||||
}
|
||||
|
||||
return sharpnessRange;
|
||||
}
|
||||
} // namespace pwlev2
|
||||
} // namespace testing
|
||||
} // namespace vibrator
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
#endif // VIBRATOR_HAL_PWLE_V2_UTILS_H
|
||||
Reference in New Issue
Block a user