Merge "Squash frequency control capability for merged multi-vibrators when missing frequency profile." into tm-qpr-dev am: 8cd94e33fa

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20441507

Change-Id: I44074f4c07e7070d8ff7931b56f8f4cee9b4f611
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
TreeHugger Robot
2022-11-14 13:05:51 +00:00
committed by Automerger Merge Worker
2 changed files with 69 additions and 11 deletions

View File

@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage; import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context; import android.content.Context;
import android.hardware.vibrator.IVibrator;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.Log; import android.util.Log;
import android.util.Range; import android.util.Range;
@@ -313,8 +314,14 @@ public class SystemVibrator extends Vibrator {
private static final float EPSILON = 1e-5f; private static final float EPSILON = 1e-5f;
public MultiVibratorInfo(VibratorInfo[] vibrators) { public MultiVibratorInfo(VibratorInfo[] vibrators) {
// Need to use an extra constructor to share the computation in super initialization.
this(vibrators, frequencyProfileIntersection(vibrators));
}
private MultiVibratorInfo(VibratorInfo[] vibrators,
VibratorInfo.FrequencyProfile mergedProfile) {
super(/* id= */ -1, super(/* id= */ -1,
capabilitiesIntersection(vibrators), capabilitiesIntersection(vibrators, mergedProfile.isEmpty()),
supportedEffectsIntersection(vibrators), supportedEffectsIntersection(vibrators),
supportedBrakingIntersection(vibrators), supportedBrakingIntersection(vibrators),
supportedPrimitivesAndDurationsIntersection(vibrators), supportedPrimitivesAndDurationsIntersection(vibrators),
@@ -323,14 +330,19 @@ public class SystemVibrator extends Vibrator {
integerLimitIntersection(vibrators, VibratorInfo::getPwlePrimitiveDurationMax), integerLimitIntersection(vibrators, VibratorInfo::getPwlePrimitiveDurationMax),
integerLimitIntersection(vibrators, VibratorInfo::getPwleSizeMax), integerLimitIntersection(vibrators, VibratorInfo::getPwleSizeMax),
floatPropertyIntersection(vibrators, VibratorInfo::getQFactor), floatPropertyIntersection(vibrators, VibratorInfo::getQFactor),
frequencyProfileIntersection(vibrators)); mergedProfile);
} }
private static int capabilitiesIntersection(VibratorInfo[] infos) { private static int capabilitiesIntersection(VibratorInfo[] infos,
boolean frequencyProfileIsEmpty) {
int intersection = ~0; int intersection = ~0;
for (VibratorInfo info : infos) { for (VibratorInfo info : infos) {
intersection &= info.getCapabilities(); intersection &= info.getCapabilities();
} }
if (frequencyProfileIsEmpty) {
// Revoke frequency control if the merged frequency profile ended up empty.
intersection &= ~IVibrator.CAP_FREQUENCY_CONTROL;
}
return intersection; return intersection;
} }

View File

@@ -246,10 +246,12 @@ public class VibratorTest {
@Test @Test
public void getQFactorAndResonantFrequency_differentValues_returnsNaN() { public void getQFactorAndResonantFrequency_differentValues_returnsNaN() {
VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1) VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setQFactor(1f) .setQFactor(1f)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, null)) .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, null))
.build(); .build();
VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2) VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setQFactor(2f) .setQFactor(2f)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(2, 2, 2, null)) .setFrequencyProfile(new VibratorInfo.FrequencyProfile(2, 2, 2, null))
.build(); .build();
@@ -258,6 +260,7 @@ public class VibratorTest {
assertTrue(Float.isNaN(info.getQFactor())); assertTrue(Float.isNaN(info.getQFactor()));
assertTrue(Float.isNaN(info.getResonantFrequencyHz())); assertTrue(Float.isNaN(info.getResonantFrequencyHz()));
assertEmptyFrequencyProfileAndControl(info);
// One vibrator with values undefined. // One vibrator with values undefined.
VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 3).build(); VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 3).build();
@@ -266,16 +269,19 @@ public class VibratorTest {
assertTrue(Float.isNaN(info.getQFactor())); assertTrue(Float.isNaN(info.getQFactor()));
assertTrue(Float.isNaN(info.getResonantFrequencyHz())); assertTrue(Float.isNaN(info.getResonantFrequencyHz()));
assertEmptyFrequencyProfileAndControl(info);
} }
@Test @Test
public void getQFactorAndResonantFrequency_sameValues_returnsValue() { public void getQFactorAndResonantFrequency_sameValues_returnsValue() {
VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1) VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setQFactor(10f) .setQFactor(10f)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile( .setFrequencyProfile(new VibratorInfo.FrequencyProfile(
/* resonantFrequencyHz= */ 11, 10, 0.5f, null)) /* resonantFrequencyHz= */ 11, 10, 0.5f, null))
.build(); .build();
VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2) VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setQFactor(10f) .setQFactor(10f)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile( .setFrequencyProfile(new VibratorInfo.FrequencyProfile(
/* resonantFrequencyHz= */ 11, 5, 1, null)) /* resonantFrequencyHz= */ 11, 5, 1, null))
@@ -285,113 +291,131 @@ public class VibratorTest {
assertEquals(10f, info.getQFactor(), TEST_TOLERANCE); assertEquals(10f, info.getQFactor(), TEST_TOLERANCE);
assertEquals(11f, info.getResonantFrequencyHz(), TEST_TOLERANCE); assertEquals(11f, info.getResonantFrequencyHz(), TEST_TOLERANCE);
// No frequency range defined.
assertTrue(info.getFrequencyProfile().isEmpty());
assertEquals(false, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
} }
@Test @Test
public void getFrequencyProfile_noVibrator_returnsEmpty() { public void getFrequencyProfile_noVibrator_returnsEmpty() {
VibratorInfo info = new SystemVibrator.NoVibratorInfo(); VibratorInfo info = new SystemVibrator.NoVibratorInfo();
assertTrue(info.getFrequencyProfile().isEmpty()); assertEmptyFrequencyProfileAndControl(info);
} }
@Test @Test
public void getFrequencyProfile_differentResonantFrequencyOrResolutionValues_returnsEmpty() { public void getFrequencyProfile_differentResonantFrequencyOrResolutionValues_returnsEmpty() {
VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1) VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1,
new float[] { 0, 1 })) new float[] { 0, 1 }))
.build(); .build();
VibratorInfo differentResonantFrequency = new VibratorInfo.Builder(/* id= */ 2) VibratorInfo differentResonantFrequency = new VibratorInfo.Builder(/* id= */ 2)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(2, 1, 1, .setFrequencyProfile(new VibratorInfo.FrequencyProfile(2, 1, 1,
new float[] { 0, 1 })) new float[] { 0, 1 }))
.build(); .build();
VibratorInfo info = new SystemVibrator.MultiVibratorInfo( VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
new VibratorInfo[]{firstVibrator, differentResonantFrequency}); new VibratorInfo[]{firstVibrator, differentResonantFrequency});
assertTrue(info.getFrequencyProfile().isEmpty()); assertEmptyFrequencyProfileAndControl(info);
VibratorInfo differentFrequencyResolution = new VibratorInfo.Builder(/* id= */ 2) VibratorInfo differentFrequencyResolution = new VibratorInfo.Builder(/* id= */ 2)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 2, .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 2,
new float[] { 0, 1 })) new float[] { 0, 1 }))
.build(); .build();
info = new SystemVibrator.MultiVibratorInfo( info = new SystemVibrator.MultiVibratorInfo(
new VibratorInfo[]{firstVibrator, differentFrequencyResolution}); new VibratorInfo[]{firstVibrator, differentFrequencyResolution});
assertTrue(info.getFrequencyProfile().isEmpty()); assertEmptyFrequencyProfileAndControl(info);
} }
@Test @Test
public void getFrequencyProfile_missingValues_returnsEmpty() { public void getFrequencyProfile_missingValues_returnsEmpty() {
VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1) VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1,
new float[] { 0, 1 })) new float[] { 0, 1 }))
.build(); .build();
VibratorInfo missingResonantFrequency = new VibratorInfo.Builder(/* id= */ 2) VibratorInfo missingResonantFrequency = new VibratorInfo.Builder(/* id= */ 2)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(Float.NaN, 1, 1, .setFrequencyProfile(new VibratorInfo.FrequencyProfile(Float.NaN, 1, 1,
new float[] { 0, 1 })) new float[] { 0, 1 }))
.build(); .build();
VibratorInfo info = new SystemVibrator.MultiVibratorInfo( VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
new VibratorInfo[]{firstVibrator, missingResonantFrequency}); new VibratorInfo[]{firstVibrator, missingResonantFrequency});
assertTrue(info.getFrequencyProfile().isEmpty()); assertEmptyFrequencyProfileAndControl(info);
VibratorInfo missingMinFrequency = new VibratorInfo.Builder(/* id= */ 2) VibratorInfo missingMinFrequency = new VibratorInfo.Builder(/* id= */ 2)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, Float.NaN, 1, .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, Float.NaN, 1,
new float[] { 0, 1 })) new float[] { 0, 1 }))
.build(); .build();
info = new SystemVibrator.MultiVibratorInfo( info = new SystemVibrator.MultiVibratorInfo(
new VibratorInfo[]{firstVibrator, missingMinFrequency}); new VibratorInfo[]{firstVibrator, missingMinFrequency});
assertTrue(info.getFrequencyProfile().isEmpty()); assertEmptyFrequencyProfileAndControl(info);
VibratorInfo missingFrequencyResolution = new VibratorInfo.Builder(/* id= */ 2) VibratorInfo missingFrequencyResolution = new VibratorInfo.Builder(/* id= */ 2)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, Float.NaN, .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, Float.NaN,
new float[] { 0, 1 })) new float[] { 0, 1 }))
.build(); .build();
info = new SystemVibrator.MultiVibratorInfo( info = new SystemVibrator.MultiVibratorInfo(
new VibratorInfo[]{firstVibrator, missingFrequencyResolution}); new VibratorInfo[]{firstVibrator, missingFrequencyResolution});
assertTrue(info.getFrequencyProfile().isEmpty()); assertEmptyFrequencyProfileAndControl(info);
VibratorInfo missingMaxAmplitudes = new VibratorInfo.Builder(/* id= */ 2) VibratorInfo missingMaxAmplitudes = new VibratorInfo.Builder(/* id= */ 2)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, null)) .setFrequencyProfile(new VibratorInfo.FrequencyProfile(1, 1, 1, null))
.build(); .build();
info = new SystemVibrator.MultiVibratorInfo( info = new SystemVibrator.MultiVibratorInfo(
new VibratorInfo[]{firstVibrator, missingMaxAmplitudes}); new VibratorInfo[]{firstVibrator, missingMaxAmplitudes});
assertTrue(info.getFrequencyProfile().isEmpty()); assertEmptyFrequencyProfileAndControl(info);
} }
@Test @Test
public void getFrequencyProfile_unalignedMaxAmplitudes_returnsEmpty() { public void getFrequencyProfile_unalignedMaxAmplitudes_returnsEmpty() {
VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1) VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10, 0.5f, .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10, 0.5f,
new float[] { 0, 1, 1, 0 })) new float[] { 0, 1, 1, 0 }))
.build(); .build();
VibratorInfo unalignedMinFrequency = new VibratorInfo.Builder(/* id= */ 2) VibratorInfo unalignedMinFrequency = new VibratorInfo.Builder(/* id= */ 2)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.1f, 0.5f, .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.1f, 0.5f,
new float[] { 0, 1, 1, 0 })) new float[] { 0, 1, 1, 0 }))
.build(); .build();
VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 2) VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 2)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f, .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
new float[] { 0, 1, 1, 0 })) new float[] { 0, 1, 1, 0 }))
.build(); .build();
VibratorInfo info = new SystemVibrator.MultiVibratorInfo( VibratorInfo info = new SystemVibrator.MultiVibratorInfo(
new VibratorInfo[]{firstVibrator, unalignedMinFrequency, thirdVibrator}); new VibratorInfo[]{firstVibrator, unalignedMinFrequency, thirdVibrator});
assertTrue(info.getFrequencyProfile().isEmpty()); assertEmptyFrequencyProfileAndControl(info);
} }
@Test @Test
public void getFrequencyProfile_alignedProfiles_returnsIntersection() { public void getFrequencyProfile_alignedProfiles_returnsIntersection() {
VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1) VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10, 0.5f, .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10, 0.5f,
new float[] { 0.5f, 1, 1, 0.5f })) new float[] { 0.5f, 1, 1, 0.5f }))
.build(); .build();
VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2) VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f, .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
new float[] { 1, 1, 1 })) new float[] { 1, 1, 1 }))
.build(); .build();
VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 3) VibratorInfo thirdVibrator = new VibratorInfo.Builder(/* id= */ 3)
.setCapabilities(IVibrator.CAP_FREQUENCY_CONTROL)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f, .setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
new float[] { 0.8f, 1, 0.8f, 0.5f })) new float[] { 0.8f, 1, 0.8f, 0.5f }))
.build(); .build();
@@ -401,6 +425,20 @@ public class VibratorTest {
assertEquals( assertEquals(
new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f, new float[] { 0.8f, 1, 0.5f }), new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f, new float[] { 0.8f, 1, 0.5f }),
info.getFrequencyProfile()); info.getFrequencyProfile());
assertEquals(true, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
// Third vibrator without frequency control capability.
thirdVibrator = new VibratorInfo.Builder(/* id= */ 3)
.setFrequencyProfile(new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f,
new float[] { 0.8f, 1, 0.8f, 0.5f }))
.build();
info = new SystemVibrator.MultiVibratorInfo(
new VibratorInfo[]{firstVibrator, secondVibrator, thirdVibrator});
assertEquals(
new VibratorInfo.FrequencyProfile(11, 10.5f, 0.5f, new float[] { 0.8f, 1, 0.5f }),
info.getFrequencyProfile());
assertEquals(false, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
} }
@Test @Test
@@ -547,4 +585,12 @@ public class VibratorTest {
VibrationAttributes vibrationAttributes = captor.getValue(); VibrationAttributes vibrationAttributes = captor.getValue();
assertEquals(new VibrationAttributes.Builder().build(), vibrationAttributes); assertEquals(new VibrationAttributes.Builder().build(), vibrationAttributes);
} }
/**
* Asserts that the frequency profile is empty, and therefore frequency control isn't supported.
*/
void assertEmptyFrequencyProfileAndControl(VibratorInfo info) {
assertTrue(info.getFrequencyProfile().isEmpty());
assertEquals(false, info.hasCapability(IVibrator.CAP_FREQUENCY_CONTROL));
}
} }