Use linear interpolator in VibratorInfo bandwidth curve
Change VibratorInfo.FrequencyProfile to use a linear interpolation for the max amplitude supported by frequency values between two measurement entries in the HAL bandwidth returned. Bug: 203785430 Test: VibratorInfoTest Change-Id: I56e998df40698be87a713ca9013380c0e938e165
This commit is contained in:
@@ -573,21 +573,29 @@ public class VibratorInfo implements Parcelable {
|
||||
* supported frequency range is empty.
|
||||
*/
|
||||
public float getMaxAmplitude(float frequencyHz) {
|
||||
if (isEmpty() || Float.isNaN(frequencyHz)) {
|
||||
if (isEmpty() || Float.isNaN(frequencyHz) || !mFrequencyRangeHz.contains(frequencyHz)) {
|
||||
// Unsupported frequency requested, vibrator cannot play at this frequency.
|
||||
return 0;
|
||||
}
|
||||
float position = (frequencyHz - mMinFrequencyHz) / mFrequencyResolutionHz;
|
||||
int floorIndex = (int) Math.floor(position);
|
||||
int ceilIndex = (int) Math.ceil(position);
|
||||
if (floorIndex < 0 || floorIndex >= mMaxAmplitudes.length) {
|
||||
return 0;
|
||||
}
|
||||
if (floorIndex != ceilIndex && ceilIndex < mMaxAmplitudes.length) {
|
||||
// Value in between two mapped frequency values, use the lowest supported one.
|
||||
return MathUtils.min(mMaxAmplitudes[floorIndex], mMaxAmplitudes[ceilIndex]);
|
||||
}
|
||||
return mMaxAmplitudes[floorIndex];
|
||||
|
||||
// Subtract minFrequencyHz to simplify offset calculations.
|
||||
float mappingFreq = frequencyHz - mMinFrequencyHz;
|
||||
|
||||
// Find the bucket to interpolate within.
|
||||
// Any calculated index should be safe, except exactly equal to max amplitude can be
|
||||
// one step too high, so constrain it to guarantee safety.
|
||||
int startIdx = MathUtils.constrain(
|
||||
/* amount= */ (int) Math.floor(mappingFreq / mFrequencyResolutionHz),
|
||||
/* low= */ 0, /* high= */ mMaxAmplitudes.length - 1);
|
||||
int nextIdx = MathUtils.constrain(
|
||||
/* amount= */ startIdx + 1,
|
||||
/* low= */ 0, /* high= */ mMaxAmplitudes.length - 1);
|
||||
|
||||
// Linearly interpolate the amplitudes based on the frequency range of the bucket.
|
||||
return MathUtils.constrainedMap(
|
||||
mMaxAmplitudes[startIdx], mMaxAmplitudes[nextIdx],
|
||||
startIdx * mFrequencyResolutionHz, nextIdx * mFrequencyResolutionHz,
|
||||
mappingFreq);
|
||||
}
|
||||
|
||||
/** Returns the raw list of maximum relative output accelerations from the vibrator. */
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.os;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.hardware.vibrator.Braking;
|
||||
@@ -144,6 +145,7 @@ public class VibratorInfoTest {
|
||||
assertTrue(
|
||||
new VibratorInfo.Builder(TEST_VIBRATOR_ID).build().getFrequencyProfile().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFrequencyProfile_invalidValuesCreatesEmptyProfile() {
|
||||
// Invalid, contains NaN values or empty array.
|
||||
@@ -172,6 +174,31 @@ public class VibratorInfoTest {
|
||||
150, 50, /* frequencyResolutionHz= */ 10, TEST_AMPLITUDE_MAP).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFrequencyRangeHz_emptyProfileReturnsNull() {
|
||||
assertNull(new VibratorInfo.FrequencyProfile(
|
||||
Float.NaN, 50, 25, TEST_AMPLITUDE_MAP).getFrequencyRangeHz());
|
||||
assertNull(new VibratorInfo.FrequencyProfile(
|
||||
150, Float.NaN, 25, TEST_AMPLITUDE_MAP).getFrequencyRangeHz());
|
||||
assertNull(new VibratorInfo.FrequencyProfile(
|
||||
150, 50, Float.NaN, TEST_AMPLITUDE_MAP).getFrequencyRangeHz());
|
||||
assertNull(new VibratorInfo.FrequencyProfile(150, 50, 25, null).getFrequencyRangeHz());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFrequencyRangeHz_validProfileReturnsMappedValues() {
|
||||
VibratorInfo.FrequencyProfile profile = new VibratorInfo.FrequencyProfile(
|
||||
/* resonantFrequencyHz= */ 150,
|
||||
/* minFrequencyHz= */ 50,
|
||||
/* frequencyResolutionHz= */ 25,
|
||||
/* maxAmplitudes= */ new float[]{
|
||||
/* 50Hz= */ 0.1f, 0.2f, 0.4f, 0.8f, /* 150Hz= */ 1f, 0.9f,
|
||||
/* 200Hz= */ 0.8f});
|
||||
|
||||
assertEquals(50f, profile.getFrequencyRangeHz().getLower(), TEST_TOLERANCE);
|
||||
assertEquals(200f, profile.getFrequencyRangeHz().getUpper(), TEST_TOLERANCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMaxAmplitude_emptyProfileReturnsAlwaysZero() {
|
||||
VibratorInfo.FrequencyProfile profile = EMPTY_FREQUENCY_PROFILE;
|
||||
@@ -191,7 +218,7 @@ public class VibratorInfoTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMaxAmplitude_validprofileReturnsMappedValues() {
|
||||
public void testGetMaxAmplitude_validProfileReturnsMappedValues() {
|
||||
VibratorInfo.FrequencyProfile profile = new VibratorInfo.FrequencyProfile(
|
||||
/* resonantFrequencyHz= */ 150,
|
||||
/* minFrequencyHz= */ 50,
|
||||
@@ -200,16 +227,23 @@ public class VibratorInfoTest {
|
||||
/* 50Hz= */ 0.1f, 0.2f, 0.4f, 0.8f, /* 150Hz= */ 1f, 0.9f,
|
||||
/* 200Hz= */ 0.8f});
|
||||
|
||||
// Values in the max amplitudes array should return exact measurement.
|
||||
assertEquals(1f, profile.getMaxAmplitude(150f), TEST_TOLERANCE);
|
||||
assertEquals(0.9f, profile.getMaxAmplitude(175f), TEST_TOLERANCE);
|
||||
assertEquals(0.8f, profile.getMaxAmplitude(125f), TEST_TOLERANCE);
|
||||
|
||||
// Min and max frequencies should return exact measurement from array.
|
||||
assertEquals(0.8f, profile.getMaxAmplitude(200f), TEST_TOLERANCE);
|
||||
assertEquals(0.1f, profile.getMaxAmplitude(50f), TEST_TOLERANCE);
|
||||
|
||||
// 145Hz maps to the max amplitude for 125Hz, which is lower.
|
||||
assertEquals(0.8f, profile.getMaxAmplitude(145f), TEST_TOLERANCE); // 145Hz
|
||||
// 185Hz maps to the max amplitude for 200Hz, which is lower.
|
||||
assertEquals(0.8f, profile.getMaxAmplitude(185f), TEST_TOLERANCE); // 185Hz
|
||||
// Values outside [50Hz, 200Hz] just return 0.
|
||||
assertEquals(0f, profile.getMaxAmplitude(49f), TEST_TOLERANCE);
|
||||
assertEquals(0f, profile.getMaxAmplitude(201f), TEST_TOLERANCE);
|
||||
|
||||
// 145Hz maps to linear value between 125Hz and 150Hz max amplitudes 0.8 and 1.
|
||||
assertEquals(0.96f, profile.getMaxAmplitude(145f), TEST_TOLERANCE);
|
||||
// 185Hz maps to linear value between 175Hz and 200Hz max amplitudes 0.9 and 0.8.
|
||||
assertEquals(0.86f, profile.getMaxAmplitude(185f), TEST_TOLERANCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user