Merge "Apply intensity settings to composed vibration effects" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
896cdcca42
@@ -897,6 +897,34 @@ public abstract class VibrationEffect implements Parcelable {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale all primitives of this effect.
|
||||
*
|
||||
* @param gamma the gamma adjustment to apply
|
||||
* @param maxAmplitude the new maximum amplitude of the effect, must be between 0 and
|
||||
* MAX_AMPLITUDE
|
||||
* @throws IllegalArgumentException if maxAmplitude less than 0 or more than MAX_AMPLITUDE
|
||||
*
|
||||
* @return A {@link Composed} effect with same but scaled primitives.
|
||||
*/
|
||||
public Composed scale(float gamma, int maxAmplitude) {
|
||||
if (maxAmplitude > MAX_AMPLITUDE || maxAmplitude < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Amplitude is negative or greater than MAX_AMPLITUDE");
|
||||
}
|
||||
if (gamma == 1.0f && maxAmplitude == MAX_AMPLITUDE) {
|
||||
// Just return a copy of the original if there's no scaling to be done.
|
||||
return new Composed(mPrimitiveEffects);
|
||||
}
|
||||
List<Composition.PrimitiveEffect> scaledPrimitives = new ArrayList<>();
|
||||
for (Composition.PrimitiveEffect primitive : mPrimitiveEffects) {
|
||||
float adjustedScale = MathUtils.pow(primitive.scale, gamma);
|
||||
float newScale = adjustedScale * maxAmplitude / (float) MAX_AMPLITUDE;
|
||||
scaledPrimitives.add(new Composition.PrimitiveEffect(
|
||||
primitive.id, newScale, primitive.delay));
|
||||
}
|
||||
return new Composed(scaledPrimitives);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
|
||||
@@ -22,9 +22,12 @@ import static junit.framework.Assert.assertNull;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static junit.framework.Assert.fail;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ContentInterface;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
@@ -37,6 +40,8 @@ import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class VibrationEffectTest {
|
||||
private static final float SCALE_TOLERANCE = 1e-2f;
|
||||
|
||||
private static final String RINGTONE_URI_1 = "content://test/system/ringtone_1";
|
||||
private static final String RINGTONE_URI_2 = "content://test/system/ringtone_2";
|
||||
private static final String RINGTONE_URI_3 = "content://test/system/ringtone_3";
|
||||
@@ -54,6 +59,12 @@ public class VibrationEffectTest {
|
||||
VibrationEffect.createOneShot(TEST_TIMING, VibrationEffect.DEFAULT_AMPLITUDE);
|
||||
private static final VibrationEffect TEST_WAVEFORM =
|
||||
VibrationEffect.createWaveform(TEST_TIMINGS, TEST_AMPLITUDES, -1);
|
||||
private static final VibrationEffect TEST_COMPOSED =
|
||||
VibrationEffect.startComposition()
|
||||
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
|
||||
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f, 10)
|
||||
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0, 100)
|
||||
.compose();
|
||||
|
||||
@Test
|
||||
public void getRingtones_noPrebakedRingtones() {
|
||||
@@ -123,8 +134,14 @@ public class VibrationEffectTest {
|
||||
|
||||
@Test
|
||||
public void testScaleWaveform() {
|
||||
VibrationEffect.Waveform scaled =
|
||||
((VibrationEffect.Waveform) TEST_WAVEFORM).scale(1.1f, 200);
|
||||
VibrationEffect.Waveform initial = (VibrationEffect.Waveform) TEST_WAVEFORM;
|
||||
|
||||
VibrationEffect.Waveform copied = initial.scale(1f, 255);
|
||||
assertEquals(255, copied.getAmplitudes()[0]);
|
||||
assertEquals(0, copied.getAmplitudes()[1]);
|
||||
assertEquals(-1, copied.getAmplitudes()[2]);
|
||||
|
||||
VibrationEffect.Waveform scaled = initial.scale(1.1f, 200);
|
||||
assertEquals(200, scaled.getAmplitudes()[0]);
|
||||
assertEquals(0, scaled.getAmplitudes()[1]);
|
||||
}
|
||||
@@ -156,6 +173,66 @@ public class VibrationEffectTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScaleComposed() {
|
||||
VibrationEffect.Composed initial = (VibrationEffect.Composed) TEST_COMPOSED;
|
||||
|
||||
VibrationEffect.Composed copied = initial.scale(1, 255);
|
||||
assertEquals(1f, copied.getPrimitiveEffects().get(0).scale);
|
||||
assertEquals(0.5f, copied.getPrimitiveEffects().get(1).scale);
|
||||
assertEquals(0f, copied.getPrimitiveEffects().get(2).scale);
|
||||
|
||||
VibrationEffect.Composed halved = initial.scale(1, 128);
|
||||
assertEquals(0.5f, halved.getPrimitiveEffects().get(0).scale, SCALE_TOLERANCE);
|
||||
assertEquals(0.25f, halved.getPrimitiveEffects().get(1).scale, SCALE_TOLERANCE);
|
||||
assertEquals(0f, halved.getPrimitiveEffects().get(2).scale);
|
||||
|
||||
VibrationEffect.Composed scaledUp = initial.scale(0.5f, 255);
|
||||
assertEquals(1f, scaledUp.getPrimitiveEffects().get(0).scale); // does not scale up from 1
|
||||
assertTrue(0.5f < scaledUp.getPrimitiveEffects().get(1).scale);
|
||||
assertEquals(0f, scaledUp.getPrimitiveEffects().get(2).scale);
|
||||
|
||||
VibrationEffect.Composed restored = scaledUp.scale(2, 255);
|
||||
assertEquals(1f, restored.getPrimitiveEffects().get(0).scale, SCALE_TOLERANCE);
|
||||
assertEquals(0.5f, restored.getPrimitiveEffects().get(1).scale, SCALE_TOLERANCE);
|
||||
assertEquals(0f, restored.getPrimitiveEffects().get(2).scale);
|
||||
|
||||
VibrationEffect.Composed scaledDown = initial.scale(2, 255);
|
||||
assertEquals(1f, scaledDown.getPrimitiveEffects().get(0).scale, SCALE_TOLERANCE);
|
||||
assertTrue(0.5f > scaledDown.getPrimitiveEffects().get(1).scale);
|
||||
assertEquals(0f, scaledDown.getPrimitiveEffects().get(2).scale, SCALE_TOLERANCE);
|
||||
|
||||
VibrationEffect.Composed changeMax = initial.scale(1f, 51);
|
||||
assertEquals(0.2f, changeMax.getPrimitiveEffects().get(0).scale, SCALE_TOLERANCE);
|
||||
assertEquals(0.1f, changeMax.getPrimitiveEffects().get(1).scale, SCALE_TOLERANCE);
|
||||
assertEquals(0f, changeMax.getPrimitiveEffects().get(2).scale);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScaleComposedFailsWhenMaxAmplitudeAboveThreshold() {
|
||||
try {
|
||||
((VibrationEffect.Composed) TEST_COMPOSED).scale(1.1f, 1000);
|
||||
fail("Max amplitude above threshold, should throw IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScaleAppliesSameAdjustmentsOnAllEffects() {
|
||||
VibrationEffect.OneShot oneShot = new VibrationEffect.OneShot(TEST_TIMING, TEST_AMPLITUDE);
|
||||
VibrationEffect.Waveform waveform = new VibrationEffect.Waveform(
|
||||
new long[] { TEST_TIMING }, new int[]{ TEST_AMPLITUDE }, -1);
|
||||
VibrationEffect.Composed composed =
|
||||
(VibrationEffect.Composed) VibrationEffect.startComposition()
|
||||
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, TEST_AMPLITUDE / 255f)
|
||||
.compose();
|
||||
|
||||
assertEquals(oneShot.scale(2f, 128).getAmplitude(),
|
||||
waveform.scale(2f, 128).getAmplitudes()[0]);
|
||||
assertEquals(oneShot.scale(2f, 128).getAmplitude() / 255f, // convert amplitude to scale
|
||||
composed.scale(2f, 128).getPrimitiveEffects().get(0).scale,
|
||||
SCALE_TOLERANCE);
|
||||
}
|
||||
|
||||
private Resources mockRingtoneResources() {
|
||||
return mockRingtoneResources(new String[] {
|
||||
@@ -172,9 +249,22 @@ public class VibrationEffectTest {
|
||||
return mockResources;
|
||||
}
|
||||
|
||||
private Context mockContext(Resources r) {
|
||||
Context ctx = mock(Context.class);
|
||||
when(ctx.getResources()).thenReturn(r);
|
||||
return ctx;
|
||||
private Context mockContext(Resources resources) {
|
||||
Context context = mock(Context.class);
|
||||
ContentInterface contentInterface = mock(ContentInterface.class);
|
||||
ContentResolver contentResolver = ContentResolver.wrap(contentInterface);
|
||||
|
||||
try {
|
||||
// ContentResolver#uncanonicalize is final, so we need to mock the ContentInterface it
|
||||
// delegates the call to for the tests that require matching with the mocked URIs.
|
||||
when(contentInterface.uncanonicalize(any())).then(
|
||||
invocation -> invocation.getArgument(0));
|
||||
when(context.getContentResolver()).thenReturn(contentResolver);
|
||||
when(context.getResources()).thenReturn(resources);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1034,6 +1034,9 @@ public class VibratorService extends IVibratorService.Stub
|
||||
VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
|
||||
waveform = waveform.resolve(mDefaultVibrationAmplitude);
|
||||
scaledEffect = waveform.scale(scale.gamma, scale.maxAmplitude);
|
||||
} else if (vib.effect instanceof VibrationEffect.Composed) {
|
||||
VibrationEffect.Composed composed = (VibrationEffect.Composed) vib.effect;
|
||||
scaledEffect = composed.scale(scale.gamma, scale.maxAmplitude);
|
||||
} else {
|
||||
Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user