Introduce CTS for Vibrator frequency APIs
Add tests to ensure that devices with frequency control will return
non-empty frequency profiles with valid values for output acceleration
and supported frequencies.
Also introduce coverage tests to the new resonant frequency and Q-factor
APIs.
Bug: 211750173
Test: VibratorTest
Change-Id: Id65d5723473201b4b92aec812cbbd45c77a84631
diff --git a/tests/tests/os/src/android/os/cts/VibratorManagerTest.java b/tests/tests/os/src/android/os/cts/VibratorManagerTest.java
index 2ddecab..f0fb42e 100644
--- a/tests/tests/os/src/android/os/cts/VibratorManagerTest.java
+++ b/tests/tests/os/src/android/os/cts/VibratorManagerTest.java
@@ -24,7 +24,6 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
@@ -35,6 +34,7 @@
import android.os.Vibrator;
import android.os.Vibrator.OnVibratorStateChangedListener;
import android.os.VibratorManager;
+import android.os.vibrator.VibratorFrequencyProfile;
import android.util.SparseArray;
import androidx.test.filters.LargeTest;
@@ -69,6 +69,12 @@
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ private static final float TEST_TOLERANCE = 1e-5f;
+
+ private static final float MINIMUM_ACCEPTED_MEASUREMENT_INTERVAL_FREQUENCY = 1f;
+ private static final float MINIMUM_ACCEPTED_FREQUENCY = 1f;
+ private static final float MAXIMUM_ACCEPTED_FREQUENCY = 2_000f;
+
private static final long CALLBACK_TIMEOUT_MILLIS = 5_000;
private static final VibrationAttributes VIBRATION_ATTRIBUTES =
new VibrationAttributes.Builder()
@@ -242,17 +248,81 @@
}
@Test
- public void testVibrator() {
+ public void testSingleVibratorIsPresent() {
for (int vibratorId : mVibratorManager.getVibratorIds()) {
Vibrator vibrator = mVibratorManager.getVibrator(vibratorId);
assertNotNull(vibrator);
assertEquals(vibratorId, vibrator.getId());
assertTrue(vibrator.hasVibrator());
+ }
+ }
- // Just check these methods will not crash.
- // We don't really have a way to test if the device supports each effect or not.
+ @Test
+ public void testSingleVibratorAmplitudeAndFrequencyControls() {
+ for (int vibratorId : mVibratorManager.getVibratorIds()) {
+ Vibrator vibrator = mVibratorManager.getVibrator(vibratorId);
+ assertNotNull(vibrator);
+
+ // Just check this method will not crash.
vibrator.hasAmplitudeControl();
+ // Single vibrators should return the frequency profile when it has frequency control.
+ assertEquals(vibrator.hasFrequencyControl(),
+ vibrator.getFrequencyProfile() != null);
+ }
+ }
+
+ @Test
+ public void testSingleVibratorFrequencyProfile() {
+ for (int vibratorId : mVibratorManager.getVibratorIds()) {
+ Vibrator vibrator = mVibratorManager.getVibrator(vibratorId);
+ VibratorFrequencyProfile frequencyProfile = vibrator.getFrequencyProfile();
+ if (frequencyProfile == null) {
+ continue;
+ }
+
+ float measurementIntervalHz = frequencyProfile.getMaxAmplitudeMeasurementInterval();
+ assertTrue(measurementIntervalHz >= MINIMUM_ACCEPTED_MEASUREMENT_INTERVAL_FREQUENCY);
+
+ float resonantFrequency = vibrator.getResonantFrequency();
+ float minFrequencyHz = frequencyProfile.getMinFrequency();
+ float maxFrequencyHz = frequencyProfile.getMaxFrequency();
+
+ assertTrue(minFrequencyHz >= MINIMUM_ACCEPTED_FREQUENCY);
+ assertTrue(maxFrequencyHz > minFrequencyHz);
+ assertTrue(maxFrequencyHz <= MAXIMUM_ACCEPTED_FREQUENCY);
+
+ if (!Float.isNaN(resonantFrequency)) {
+ // If the device has a resonant frequency, then it should be within the supported
+ // frequency range described by the profile.
+ assertTrue(resonantFrequency >= minFrequencyHz);
+ assertTrue(resonantFrequency <= maxFrequencyHz);
+ }
+
+ float[] measurements = frequencyProfile.getMaxAmplitudeMeasurements();
+
+ // There should be at least 3 points for a valid profile.
+ assertTrue(measurements.length > 2);
+ assertEquals(maxFrequencyHz,
+ minFrequencyHz + ((measurements.length - 1) * measurementIntervalHz),
+ TEST_TOLERANCE);
+
+ boolean hasPositiveMeasurement = false;
+ for (float measurement : measurements) {
+ assertTrue(measurement >= 0);
+ assertTrue(measurement <= 1);
+ hasPositiveMeasurement |= measurement > 0;
+ }
+ assertTrue(hasPositiveMeasurement);
+ }
+ }
+
+ @Test
+ public void testSingleVibratorEffectAndPrimitiveSupport() {
+ for (int vibratorId : mVibratorManager.getVibratorIds()) {
+ Vibrator vibrator = mVibratorManager.getVibrator(vibratorId);
+ assertNotNull(vibrator);
+
// Just check these methods return valid support arrays.
// We don't really have a way to test if the device supports each effect or not.
assertEquals(2, vibrator.areEffectsSupported(
@@ -260,6 +330,14 @@
assertEquals(2, vibrator.arePrimitivesSupported(
VibrationEffect.Composition.PRIMITIVE_CLICK,
VibrationEffect.Composition.PRIMITIVE_TICK).length);
+ }
+ }
+
+ @Test
+ public void testSingleVibratorVibrateAndCancel() {
+ for (int vibratorId : mVibratorManager.getVibratorIds()) {
+ Vibrator vibrator = mVibratorManager.getVibrator(vibratorId);
+ assertNotNull(vibrator);
vibrator.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE));
assertStartsVibrating(vibratorId);
diff --git a/tests/tests/os/src/android/os/cts/VibratorTest.java b/tests/tests/os/src/android/os/cts/VibratorTest.java
index 7085ba5..53fdd21 100644
--- a/tests/tests/os/src/android/os/cts/VibratorTest.java
+++ b/tests/tests/os/src/android/os/cts/VibratorTest.java
@@ -20,6 +20,8 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.after;
import static org.mockito.Mockito.clearInvocations;
@@ -34,6 +36,7 @@
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.os.Vibrator.OnVibratorStateChangedListener;
+import android.os.vibrator.VibratorFrequencyProfile;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -70,6 +73,12 @@
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ private static final float TEST_TOLERANCE = 1e-5f;
+
+ private static final float MINIMUM_ACCEPTED_MEASUREMENT_INTERVAL_FREQUENCY = 1f;
+ private static final float MINIMUM_ACCEPTED_FREQUENCY = 1f;
+ private static final float MAXIMUM_ACCEPTED_FREQUENCY = 2_000f;
+
private static final AudioAttributes AUDIO_ATTRIBUTES =
new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
@@ -112,7 +121,6 @@
VibrationAttributes.USAGE_TOUCH,
};
-
/**
* This listener is used for test helper methods like asserting it starts/stops vibrating.
* It's not strongly required that the interactions with this mock are validated by all tests.
@@ -317,6 +325,13 @@
}
@Test
+ public void testVibratorHasFrequencyControl() {
+ // Just make sure it doesn't crash when this is called; we don't really have a way to test
+ // if the frequency control works or not.
+ mVibrator.hasFrequencyControl();
+ }
+
+ @Test
public void testVibratorEffectsAreSupported() {
// Just make sure it doesn't crash when this is called and that it returns all queries;
// We don't really have a way to test if the device supports each effect or not.
@@ -365,10 +380,87 @@
}
@Test
- public void testVibratorIsVibrating() {
- if (!mVibrator.hasVibrator()) {
- return;
+ public void testVibratorResonantFrequency() {
+ // Check that the resonant frequency provided is NaN, or if it's a reasonable value.
+ float resonantFrequency = mVibrator.getResonantFrequency();
+ assertTrue(Float.isNaN(resonantFrequency)
+ || (resonantFrequency > 0 && resonantFrequency < MAXIMUM_ACCEPTED_FREQUENCY));
+ }
+
+ @Test
+ public void testVibratorQFactor() {
+ // Just make sure it doesn't crash when this is called;
+ // We don't really have a way to test if the device provides the Q-factor or not.
+ mVibrator.getQFactor();
+ }
+
+ @Test
+ public void testVibratorVibratorFrequencyProfileFrequencyControl() {
+ assumeNotNull(mVibrator.getFrequencyProfile());
+
+ // If the frequency profile is present then the vibrator must have frequency control.
+ // The other implication is not true if the default vibrator represents multiple vibrators.
+ assertTrue(mVibrator.hasFrequencyControl());
+ }
+
+ @Test
+ public void testVibratorFrequencyProfileMeasurementInterval() {
+ VibratorFrequencyProfile frequencyProfile = mVibrator.getFrequencyProfile();
+ assumeNotNull(frequencyProfile);
+
+ float measurementIntervalHz = frequencyProfile.getMaxAmplitudeMeasurementInterval();
+ assertTrue(measurementIntervalHz >= MINIMUM_ACCEPTED_MEASUREMENT_INTERVAL_FREQUENCY);
+ }
+
+ @Test
+ public void testVibratorFrequencyProfileSupportedFrequencyRange() {
+ VibratorFrequencyProfile frequencyProfile = mVibrator.getFrequencyProfile();
+ assumeNotNull(frequencyProfile);
+
+ float resonantFrequency = mVibrator.getResonantFrequency();
+ float minFrequencyHz = frequencyProfile.getMinFrequency();
+ float maxFrequencyHz = frequencyProfile.getMaxFrequency();
+
+ assertTrue(minFrequencyHz >= MINIMUM_ACCEPTED_FREQUENCY);
+ assertTrue(maxFrequencyHz > minFrequencyHz);
+ assertTrue(maxFrequencyHz <= MAXIMUM_ACCEPTED_FREQUENCY);
+
+ if (!Float.isNaN(resonantFrequency)) {
+ // If the device has a resonant frequency, then it should be within the supported
+ // frequency range described by the profile.
+ assertTrue(resonantFrequency >= minFrequencyHz);
+ assertTrue(resonantFrequency <= maxFrequencyHz);
}
+ }
+
+ @Test
+ public void testVibratorFrequencyProfileOutputAccelerationMeasurements() {
+ VibratorFrequencyProfile frequencyProfile = mVibrator.getFrequencyProfile();
+ assumeNotNull(frequencyProfile);
+
+ float minFrequencyHz = frequencyProfile.getMinFrequency();
+ float maxFrequencyHz = frequencyProfile.getMaxFrequency();
+ float measurementIntervalHz = frequencyProfile.getMaxAmplitudeMeasurementInterval();
+ float[] measurements = frequencyProfile.getMaxAmplitudeMeasurements();
+
+ // There should be at least 3 points for a valid profile: min, center and max frequencies.
+ assertTrue(measurements.length > 2);
+ assertEquals(maxFrequencyHz,
+ minFrequencyHz + ((measurements.length - 1) * measurementIntervalHz),
+ TEST_TOLERANCE);
+
+ boolean hasPositiveMeasurement = false;
+ for (float measurement : measurements) {
+ assertTrue(measurement >= 0);
+ assertTrue(measurement <= 1);
+ hasPositiveMeasurement |= measurement > 0;
+ }
+ assertTrue(hasPositiveMeasurement);
+ }
+
+ @Test
+ public void testVibratorIsVibrating() {
+ assumeTrue(mVibrator.hasVibrator());
assertFalse(mVibrator.isVibrating());
@@ -384,9 +476,7 @@
@LargeTest
@Test
public void testVibratorVibratesNoLongerThanDuration() {
- if (!mVibrator.hasVibrator()) {
- return;
- }
+ assumeTrue(mVibrator.hasVibrator());
mVibrator.vibrate(1000);
assertStartsVibrating();
@@ -398,9 +488,7 @@
@LargeTest
@Test
public void testVibratorStateCallback() {
- if (!mVibrator.hasVibrator()) {
- return;
- }
+ assumeTrue(mVibrator.hasVibrator());
OnVibratorStateChangedListener listener1 = newMockStateListener();
OnVibratorStateChangedListener listener2 = newMockStateListener();
@@ -424,9 +512,7 @@
@LargeTest
@Test
public void testVibratorStateCallbackRemoval() {
- if (!mVibrator.hasVibrator()) {
- return;
- }
+ assumeTrue(mVibrator.hasVibrator());
OnVibratorStateChangedListener listener1 = newMockStateListener();
OnVibratorStateChangedListener listener2 = newMockStateListener();