Loading core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -32064,6 +32064,7 @@ package android.os { method @NonNull public boolean[] arePrimitivesSupported(@NonNull int...); method @RequiresPermission(android.Manifest.permission.VIBRATE) public abstract void cancel(); method public int getId(); method @NonNull public int[] getPrimitiveDurations(@NonNull int...); method public abstract boolean hasAmplitudeControl(); method public abstract boolean hasVibrator(); method @Deprecated @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(long); core/java/android/os/Vibrator.java +21 −0 Original line number Diff line number Diff line Loading @@ -551,6 +551,27 @@ public abstract class Vibrator { return true; } /** * Query the estimated durations of the given primitives. * * The returned array will be the same length as the query array and the value at a given index * will contain the duration in milliseconds of the effect at the same index in the querying * array. * * @param primitiveIds Which primitives to query for. * @return The duration of each primitive, with zeroes for primitives that are not supported. */ @NonNull public int[] getPrimitiveDurations( @NonNull @VibrationEffect.Composition.PrimitiveType int... primitiveIds) { VibratorInfo info = getInfo(); int[] durations = new int[primitiveIds.length]; for (int i = 0; i < primitiveIds.length; i++) { durations[i] = info.getPrimitiveDuration(primitiveIds[i]); } return durations; } /** * Turn the vibrator off. */ Loading core/java/android/os/VibratorInfo.java +121 −18 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.util.Log; import android.util.MathUtils; import android.util.Range; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import java.util.ArrayList; import java.util.Arrays; Loading @@ -51,7 +52,7 @@ public class VibratorInfo implements Parcelable { @Nullable private final SparseBooleanArray mSupportedBraking; @Nullable private final SparseBooleanArray mSupportedPrimitives; private final SparseIntArray mSupportedPrimitives; private final float mQFactor; private final FrequencyMapping mFrequencyMapping; Loading @@ -60,19 +61,37 @@ public class VibratorInfo implements Parcelable { mCapabilities = in.readLong(); mSupportedEffects = in.readSparseBooleanArray(); mSupportedBraking = in.readSparseBooleanArray(); mSupportedPrimitives = in.readSparseBooleanArray(); mSupportedPrimitives = in.readSparseIntArray(); mQFactor = in.readFloat(); mFrequencyMapping = in.readParcelable(VibratorInfo.class.getClassLoader()); } /** @hide */ /** * Default constructor. * * @param id The vibrator id. * @param capabilities All capability flags of the vibrator, defined in IVibrator.CAP_*. * @param supportedEffects All supported predefined effects, enum values from {@link * android.hardware.vibrator.Effect}. * @param supportedBraking All supported braking types, enum values from {@link Braking}. * @param supportedPrimitives All supported primitive effects, enum values from {@link * android.hardware.vibrator.CompositePrimitive}. * @param primitiveDurations A mapping of primitive durations, where indexes are enum values * from {@link android.hardware.vibrator.CompositePrimitive} and the * values are estimated durations in milliseconds. * @param qFactor The vibrator quality factor. * @param frequencyMapping The description of the vibrator supported frequencies and max * amplitude mappings. * @hide */ public VibratorInfo(int id, long capabilities, int[] supportedEffects, int[] supportedBraking, int[] supportedPrimitives, float qFactor, @NonNull FrequencyMapping frequencyMapping) { int[] supportedPrimitives, int[] primitiveDurations, float qFactor, @NonNull FrequencyMapping frequencyMapping) { mId = id; mCapabilities = capabilities; mSupportedEffects = toSparseBooleanArray(supportedEffects); mSupportedBraking = toSparseBooleanArray(supportedBraking); mSupportedPrimitives = toSparseBooleanArray(supportedPrimitives); mSupportedPrimitives = toSparseIntArray(supportedPrimitives, primitiveDurations); mQFactor = qFactor; mFrequencyMapping = frequencyMapping; } Loading Loading @@ -100,7 +119,7 @@ public class VibratorInfo implements Parcelable { dest.writeLong(mCapabilities); dest.writeSparseBooleanArray(mSupportedEffects); dest.writeSparseBooleanArray(mSupportedBraking); dest.writeSparseBooleanArray(mSupportedPrimitives); dest.writeSparseIntArray(mSupportedPrimitives); dest.writeFloat(mQFactor); dest.writeParcelable(mFrequencyMapping, flags); } Loading @@ -119,18 +138,41 @@ public class VibratorInfo implements Parcelable { return false; } VibratorInfo that = (VibratorInfo) o; if (mSupportedPrimitives == null || that.mSupportedPrimitives == null) { if (mSupportedPrimitives != that.mSupportedPrimitives) { return false; } } else { if (mSupportedPrimitives.size() != that.mSupportedPrimitives.size()) { return false; } for (int i = 0; i < mSupportedPrimitives.size(); i++) { if (mSupportedPrimitives.keyAt(i) != that.mSupportedPrimitives.keyAt(i)) { return false; } if (mSupportedPrimitives.valueAt(i) != that.mSupportedPrimitives.valueAt(i)) { return false; } } } return mId == that.mId && mCapabilities == that.mCapabilities && Objects.equals(mSupportedEffects, that.mSupportedEffects) && Objects.equals(mSupportedBraking, that.mSupportedBraking) && Objects.equals(mSupportedPrimitives, that.mSupportedPrimitives) && Objects.equals(mQFactor, that.mQFactor) && Objects.equals(mFrequencyMapping, that.mFrequencyMapping); } @Override public int hashCode() { return Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedBraking, mSupportedPrimitives, mQFactor, mFrequencyMapping); int hashCode = Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedBraking, mQFactor, mFrequencyMapping); if (mSupportedPrimitives != null) { for (int i = 0; i < mSupportedPrimitives.size(); i++) { hashCode = 31 * hashCode + mSupportedPrimitives.keyAt(i); hashCode = 31 * hashCode + mSupportedPrimitives.valueAt(i); } } return hashCode; } @Override Loading Loading @@ -206,7 +248,19 @@ public class VibratorInfo implements Parcelable { public boolean isPrimitiveSupported( @VibrationEffect.Composition.PrimitiveType int primitiveId) { return hasCapability(IVibrator.CAP_COMPOSE_EFFECTS) && mSupportedPrimitives != null && mSupportedPrimitives.get(primitiveId); && (mSupportedPrimitives.indexOfKey(primitiveId) >= 0); } /** * Query the estimated duration of given primitive. * * @param primitiveId Which primitives to query for. * @return The duration in milliseconds estimated for the primitive, or zero if primitive not * supported. */ public int getPrimitiveDuration( @VibrationEffect.Composition.PrimitiveType int primitiveId) { return mSupportedPrimitives.get(primitiveId); } /** Loading Loading @@ -364,14 +418,37 @@ public class VibratorInfo implements Parcelable { return names; } /** * Create a {@link SparseBooleanArray} from given {@code supportedKeys} where each key is mapped * to {@code true}. */ @Nullable private static SparseBooleanArray toSparseBooleanArray(int[] values) { if (values == null) { private static SparseBooleanArray toSparseBooleanArray(int[] supportedKeys) { if (supportedKeys == null) { return null; } SparseBooleanArray array = new SparseBooleanArray(); for (int value : values) { array.put(value, true); for (int key : supportedKeys) { array.put(key, true); } return array; } /** * Create a {@link SparseIntArray} from given {@code supportedKeys} where each key is mapped * to the value indexed by it. * * <p>If {@code values} is null or does not contain a given key as a index, then zero is stored * to the sparse array so it can still be used to query the supported keys. */ @Nullable private static SparseIntArray toSparseIntArray(int[] supportedKeys, int[] values) { if (supportedKeys == null) { return null; } SparseIntArray array = new SparseIntArray(); for (int key : supportedKeys) { array.put(key, (values == null || key >= values.length) ? 0 : values[key]); } return array; } Loading Loading @@ -419,7 +496,20 @@ public class VibratorInfo implements Parcelable { in.createFloatArray()); } /** @hide */ /** * Default constructor. * * @param minFrequencyHz Minimum supported frequency, in hertz. * @param resonantFrequencyHz The vibrator resonant frequency, in hertz. * @param frequencyResolutionHz The frequency resolution, in hertz, used by the max * amplitudes mapping. * @param suggestedSafeRangeHz The suggested range, in hertz, for the safe relative * frequency range represented by [-1, 1]. * @param maxAmplitudes The max amplitude supported by each supported frequency, * starting at minimum frequency with jumps of frequency * resolution. * @hide */ public FrequencyMapping(float minFrequencyHz, float resonantFrequencyHz, float frequencyResolutionHz, float suggestedSafeRangeHz, float[] maxAmplitudes) { mMinFrequencyHz = minFrequencyHz; Loading Loading @@ -547,8 +637,10 @@ public class VibratorInfo implements Parcelable { @Override public int hashCode() { return Objects.hash(mMinFrequencyHz, mFrequencyResolutionHz, mFrequencyResolutionHz, mSuggestedSafeRangeHz, mMaxAmplitudes); int hashCode = Objects.hash(mMinFrequencyHz, mFrequencyResolutionHz, mFrequencyResolutionHz, mSuggestedSafeRangeHz); hashCode = 31 * hashCode + Arrays.hashCode(mMaxAmplitudes); return hashCode; } @Override Loading Loading @@ -587,6 +679,7 @@ public class VibratorInfo implements Parcelable { private int[] mSupportedEffects = null; private int[] mSupportedBraking = null; private int[] mSupportedPrimitives = null; private int[] mPrimitiveDurations = new int[0]; private float mQFactor = Float.NaN; private FrequencyMapping mFrequencyMapping = new FrequencyMapping(Float.NaN, Float.NaN, Float.NaN, Float.NaN, null); Loading Loading @@ -627,6 +720,16 @@ public class VibratorInfo implements Parcelable { return this; } /** Configure the duration of a {@link android.hardware.vibrator.CompositePrimitive}. */ @NonNull public Builder setPrimitiveDuration(int primitiveId, int duration) { if (mPrimitiveDurations.length <= primitiveId) { mPrimitiveDurations = Arrays.copyOf(mPrimitiveDurations, primitiveId + 1); } mPrimitiveDurations[primitiveId] = duration; return this; } /** Configure the vibrator quality factor. */ @NonNull public Builder setQFactor(float qFactor) { Loading @@ -645,7 +748,7 @@ public class VibratorInfo implements Parcelable { @NonNull public VibratorInfo build() { return new VibratorInfo(mId, mCapabilities, mSupportedEffects, mSupportedBraking, mSupportedPrimitives, mQFactor, mFrequencyMapping); mSupportedPrimitives, mPrimitiveDurations, mQFactor, mFrequencyMapping); } } Loading core/tests/coretests/src/android/os/VibratorInfoTest.java +21 −1 Original line number Diff line number Diff line Loading @@ -99,6 +99,17 @@ public class VibratorInfoTest { assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK)); } @Test public void testGetPrimitiveDuration() { VibratorInfo info = new VibratorInfo.Builder(TEST_VIBRATOR_ID) .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS) .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK) .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 20) .build(); assertEquals(20, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK)); assertEquals(0, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_TICK)); } @Test public void testGetDefaultBraking_returnsFirstSupportedBraking() { assertEquals(Braking.NONE, new VibratorInfo.Builder( Loading Loading @@ -251,12 +262,14 @@ public class VibratorInfoTest { .setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL) .setSupportedEffects(VibrationEffect.EFFECT_CLICK) .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK) .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 20) .setQFactor(2f) .setFrequencyMapping(TEST_FREQUENCY_MAPPING); VibratorInfo complete = completeBuilder.build(); assertEquals(complete, complete); assertEquals(complete, completeBuilder.build()); assertEquals(complete.hashCode(), completeBuilder.build().hashCode()); VibratorInfo completeWithComposeControl = completeBuilder .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS) Loading @@ -279,6 +292,11 @@ public class VibratorInfoTest { .build(); assertNotEquals(complete, completeWithUnknownPrimitives); VibratorInfo completeWithDifferentPrimitiveDuration = completeBuilder .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 10) .build(); assertNotEquals(complete, completeWithDifferentPrimitiveDuration); VibratorInfo completeWithDifferentFrequencyMapping = completeBuilder .setFrequencyMapping(new VibratorInfo.FrequencyMapping(TEST_MIN_FREQUENCY + 10, TEST_RESONANT_FREQUENCY + 20, TEST_FREQUENCY_RESOLUTION + 5, Loading Loading @@ -314,7 +332,8 @@ public class VibratorInfoTest { VibratorInfo original = new VibratorInfo.Builder(TEST_VIBRATOR_ID) .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS) .setSupportedEffects(VibrationEffect.EFFECT_CLICK) .setSupportedPrimitives(null) .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK) .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 20) .setQFactor(Float.NaN) .setFrequencyMapping(TEST_FREQUENCY_MAPPING) .build(); Loading @@ -324,5 +343,6 @@ public class VibratorInfoTest { parcel.setDataPosition(0); VibratorInfo restored = VibratorInfo.CREATOR.createFromParcel(parcel); assertEquals(original, restored); assertEquals(original.hashCode(), restored.hashCode()); } } core/tests/coretests/src/android/os/VibratorTest.java +10 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,16 @@ public class VibratorTest { VibrationEffect.Composition.PRIMITIVE_QUICK_RISE}).length); } @Test public void getPrimitivesDurations_returnsArrayOfSameSize() { assertEquals(0, mVibratorSpy.getPrimitiveDurations(new int[0]).length); assertEquals(1, mVibratorSpy.getPrimitiveDurations( new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK}).length); assertEquals(2, mVibratorSpy.getPrimitiveDurations( new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK, VibrationEffect.Composition.PRIMITIVE_QUICK_RISE}).length); } @Test public void vibrate_withAudioAttributes_createsVibrationAttributesWithSameUsage() { VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); Loading Loading
core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -32064,6 +32064,7 @@ package android.os { method @NonNull public boolean[] arePrimitivesSupported(@NonNull int...); method @RequiresPermission(android.Manifest.permission.VIBRATE) public abstract void cancel(); method public int getId(); method @NonNull public int[] getPrimitiveDurations(@NonNull int...); method public abstract boolean hasAmplitudeControl(); method public abstract boolean hasVibrator(); method @Deprecated @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(long);
core/java/android/os/Vibrator.java +21 −0 Original line number Diff line number Diff line Loading @@ -551,6 +551,27 @@ public abstract class Vibrator { return true; } /** * Query the estimated durations of the given primitives. * * The returned array will be the same length as the query array and the value at a given index * will contain the duration in milliseconds of the effect at the same index in the querying * array. * * @param primitiveIds Which primitives to query for. * @return The duration of each primitive, with zeroes for primitives that are not supported. */ @NonNull public int[] getPrimitiveDurations( @NonNull @VibrationEffect.Composition.PrimitiveType int... primitiveIds) { VibratorInfo info = getInfo(); int[] durations = new int[primitiveIds.length]; for (int i = 0; i < primitiveIds.length; i++) { durations[i] = info.getPrimitiveDuration(primitiveIds[i]); } return durations; } /** * Turn the vibrator off. */ Loading
core/java/android/os/VibratorInfo.java +121 −18 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.util.Log; import android.util.MathUtils; import android.util.Range; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import java.util.ArrayList; import java.util.Arrays; Loading @@ -51,7 +52,7 @@ public class VibratorInfo implements Parcelable { @Nullable private final SparseBooleanArray mSupportedBraking; @Nullable private final SparseBooleanArray mSupportedPrimitives; private final SparseIntArray mSupportedPrimitives; private final float mQFactor; private final FrequencyMapping mFrequencyMapping; Loading @@ -60,19 +61,37 @@ public class VibratorInfo implements Parcelable { mCapabilities = in.readLong(); mSupportedEffects = in.readSparseBooleanArray(); mSupportedBraking = in.readSparseBooleanArray(); mSupportedPrimitives = in.readSparseBooleanArray(); mSupportedPrimitives = in.readSparseIntArray(); mQFactor = in.readFloat(); mFrequencyMapping = in.readParcelable(VibratorInfo.class.getClassLoader()); } /** @hide */ /** * Default constructor. * * @param id The vibrator id. * @param capabilities All capability flags of the vibrator, defined in IVibrator.CAP_*. * @param supportedEffects All supported predefined effects, enum values from {@link * android.hardware.vibrator.Effect}. * @param supportedBraking All supported braking types, enum values from {@link Braking}. * @param supportedPrimitives All supported primitive effects, enum values from {@link * android.hardware.vibrator.CompositePrimitive}. * @param primitiveDurations A mapping of primitive durations, where indexes are enum values * from {@link android.hardware.vibrator.CompositePrimitive} and the * values are estimated durations in milliseconds. * @param qFactor The vibrator quality factor. * @param frequencyMapping The description of the vibrator supported frequencies and max * amplitude mappings. * @hide */ public VibratorInfo(int id, long capabilities, int[] supportedEffects, int[] supportedBraking, int[] supportedPrimitives, float qFactor, @NonNull FrequencyMapping frequencyMapping) { int[] supportedPrimitives, int[] primitiveDurations, float qFactor, @NonNull FrequencyMapping frequencyMapping) { mId = id; mCapabilities = capabilities; mSupportedEffects = toSparseBooleanArray(supportedEffects); mSupportedBraking = toSparseBooleanArray(supportedBraking); mSupportedPrimitives = toSparseBooleanArray(supportedPrimitives); mSupportedPrimitives = toSparseIntArray(supportedPrimitives, primitiveDurations); mQFactor = qFactor; mFrequencyMapping = frequencyMapping; } Loading Loading @@ -100,7 +119,7 @@ public class VibratorInfo implements Parcelable { dest.writeLong(mCapabilities); dest.writeSparseBooleanArray(mSupportedEffects); dest.writeSparseBooleanArray(mSupportedBraking); dest.writeSparseBooleanArray(mSupportedPrimitives); dest.writeSparseIntArray(mSupportedPrimitives); dest.writeFloat(mQFactor); dest.writeParcelable(mFrequencyMapping, flags); } Loading @@ -119,18 +138,41 @@ public class VibratorInfo implements Parcelable { return false; } VibratorInfo that = (VibratorInfo) o; if (mSupportedPrimitives == null || that.mSupportedPrimitives == null) { if (mSupportedPrimitives != that.mSupportedPrimitives) { return false; } } else { if (mSupportedPrimitives.size() != that.mSupportedPrimitives.size()) { return false; } for (int i = 0; i < mSupportedPrimitives.size(); i++) { if (mSupportedPrimitives.keyAt(i) != that.mSupportedPrimitives.keyAt(i)) { return false; } if (mSupportedPrimitives.valueAt(i) != that.mSupportedPrimitives.valueAt(i)) { return false; } } } return mId == that.mId && mCapabilities == that.mCapabilities && Objects.equals(mSupportedEffects, that.mSupportedEffects) && Objects.equals(mSupportedBraking, that.mSupportedBraking) && Objects.equals(mSupportedPrimitives, that.mSupportedPrimitives) && Objects.equals(mQFactor, that.mQFactor) && Objects.equals(mFrequencyMapping, that.mFrequencyMapping); } @Override public int hashCode() { return Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedBraking, mSupportedPrimitives, mQFactor, mFrequencyMapping); int hashCode = Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedBraking, mQFactor, mFrequencyMapping); if (mSupportedPrimitives != null) { for (int i = 0; i < mSupportedPrimitives.size(); i++) { hashCode = 31 * hashCode + mSupportedPrimitives.keyAt(i); hashCode = 31 * hashCode + mSupportedPrimitives.valueAt(i); } } return hashCode; } @Override Loading Loading @@ -206,7 +248,19 @@ public class VibratorInfo implements Parcelable { public boolean isPrimitiveSupported( @VibrationEffect.Composition.PrimitiveType int primitiveId) { return hasCapability(IVibrator.CAP_COMPOSE_EFFECTS) && mSupportedPrimitives != null && mSupportedPrimitives.get(primitiveId); && (mSupportedPrimitives.indexOfKey(primitiveId) >= 0); } /** * Query the estimated duration of given primitive. * * @param primitiveId Which primitives to query for. * @return The duration in milliseconds estimated for the primitive, or zero if primitive not * supported. */ public int getPrimitiveDuration( @VibrationEffect.Composition.PrimitiveType int primitiveId) { return mSupportedPrimitives.get(primitiveId); } /** Loading Loading @@ -364,14 +418,37 @@ public class VibratorInfo implements Parcelable { return names; } /** * Create a {@link SparseBooleanArray} from given {@code supportedKeys} where each key is mapped * to {@code true}. */ @Nullable private static SparseBooleanArray toSparseBooleanArray(int[] values) { if (values == null) { private static SparseBooleanArray toSparseBooleanArray(int[] supportedKeys) { if (supportedKeys == null) { return null; } SparseBooleanArray array = new SparseBooleanArray(); for (int value : values) { array.put(value, true); for (int key : supportedKeys) { array.put(key, true); } return array; } /** * Create a {@link SparseIntArray} from given {@code supportedKeys} where each key is mapped * to the value indexed by it. * * <p>If {@code values} is null or does not contain a given key as a index, then zero is stored * to the sparse array so it can still be used to query the supported keys. */ @Nullable private static SparseIntArray toSparseIntArray(int[] supportedKeys, int[] values) { if (supportedKeys == null) { return null; } SparseIntArray array = new SparseIntArray(); for (int key : supportedKeys) { array.put(key, (values == null || key >= values.length) ? 0 : values[key]); } return array; } Loading Loading @@ -419,7 +496,20 @@ public class VibratorInfo implements Parcelable { in.createFloatArray()); } /** @hide */ /** * Default constructor. * * @param minFrequencyHz Minimum supported frequency, in hertz. * @param resonantFrequencyHz The vibrator resonant frequency, in hertz. * @param frequencyResolutionHz The frequency resolution, in hertz, used by the max * amplitudes mapping. * @param suggestedSafeRangeHz The suggested range, in hertz, for the safe relative * frequency range represented by [-1, 1]. * @param maxAmplitudes The max amplitude supported by each supported frequency, * starting at minimum frequency with jumps of frequency * resolution. * @hide */ public FrequencyMapping(float minFrequencyHz, float resonantFrequencyHz, float frequencyResolutionHz, float suggestedSafeRangeHz, float[] maxAmplitudes) { mMinFrequencyHz = minFrequencyHz; Loading Loading @@ -547,8 +637,10 @@ public class VibratorInfo implements Parcelable { @Override public int hashCode() { return Objects.hash(mMinFrequencyHz, mFrequencyResolutionHz, mFrequencyResolutionHz, mSuggestedSafeRangeHz, mMaxAmplitudes); int hashCode = Objects.hash(mMinFrequencyHz, mFrequencyResolutionHz, mFrequencyResolutionHz, mSuggestedSafeRangeHz); hashCode = 31 * hashCode + Arrays.hashCode(mMaxAmplitudes); return hashCode; } @Override Loading Loading @@ -587,6 +679,7 @@ public class VibratorInfo implements Parcelable { private int[] mSupportedEffects = null; private int[] mSupportedBraking = null; private int[] mSupportedPrimitives = null; private int[] mPrimitiveDurations = new int[0]; private float mQFactor = Float.NaN; private FrequencyMapping mFrequencyMapping = new FrequencyMapping(Float.NaN, Float.NaN, Float.NaN, Float.NaN, null); Loading Loading @@ -627,6 +720,16 @@ public class VibratorInfo implements Parcelable { return this; } /** Configure the duration of a {@link android.hardware.vibrator.CompositePrimitive}. */ @NonNull public Builder setPrimitiveDuration(int primitiveId, int duration) { if (mPrimitiveDurations.length <= primitiveId) { mPrimitiveDurations = Arrays.copyOf(mPrimitiveDurations, primitiveId + 1); } mPrimitiveDurations[primitiveId] = duration; return this; } /** Configure the vibrator quality factor. */ @NonNull public Builder setQFactor(float qFactor) { Loading @@ -645,7 +748,7 @@ public class VibratorInfo implements Parcelable { @NonNull public VibratorInfo build() { return new VibratorInfo(mId, mCapabilities, mSupportedEffects, mSupportedBraking, mSupportedPrimitives, mQFactor, mFrequencyMapping); mSupportedPrimitives, mPrimitiveDurations, mQFactor, mFrequencyMapping); } } Loading
core/tests/coretests/src/android/os/VibratorInfoTest.java +21 −1 Original line number Diff line number Diff line Loading @@ -99,6 +99,17 @@ public class VibratorInfoTest { assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK)); } @Test public void testGetPrimitiveDuration() { VibratorInfo info = new VibratorInfo.Builder(TEST_VIBRATOR_ID) .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS) .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK) .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 20) .build(); assertEquals(20, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK)); assertEquals(0, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_TICK)); } @Test public void testGetDefaultBraking_returnsFirstSupportedBraking() { assertEquals(Braking.NONE, new VibratorInfo.Builder( Loading Loading @@ -251,12 +262,14 @@ public class VibratorInfoTest { .setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL) .setSupportedEffects(VibrationEffect.EFFECT_CLICK) .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK) .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 20) .setQFactor(2f) .setFrequencyMapping(TEST_FREQUENCY_MAPPING); VibratorInfo complete = completeBuilder.build(); assertEquals(complete, complete); assertEquals(complete, completeBuilder.build()); assertEquals(complete.hashCode(), completeBuilder.build().hashCode()); VibratorInfo completeWithComposeControl = completeBuilder .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS) Loading @@ -279,6 +292,11 @@ public class VibratorInfoTest { .build(); assertNotEquals(complete, completeWithUnknownPrimitives); VibratorInfo completeWithDifferentPrimitiveDuration = completeBuilder .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 10) .build(); assertNotEquals(complete, completeWithDifferentPrimitiveDuration); VibratorInfo completeWithDifferentFrequencyMapping = completeBuilder .setFrequencyMapping(new VibratorInfo.FrequencyMapping(TEST_MIN_FREQUENCY + 10, TEST_RESONANT_FREQUENCY + 20, TEST_FREQUENCY_RESOLUTION + 5, Loading Loading @@ -314,7 +332,8 @@ public class VibratorInfoTest { VibratorInfo original = new VibratorInfo.Builder(TEST_VIBRATOR_ID) .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS) .setSupportedEffects(VibrationEffect.EFFECT_CLICK) .setSupportedPrimitives(null) .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK) .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 20) .setQFactor(Float.NaN) .setFrequencyMapping(TEST_FREQUENCY_MAPPING) .build(); Loading @@ -324,5 +343,6 @@ public class VibratorInfoTest { parcel.setDataPosition(0); VibratorInfo restored = VibratorInfo.CREATOR.createFromParcel(parcel); assertEquals(original, restored); assertEquals(original.hashCode(), restored.hashCode()); } }
core/tests/coretests/src/android/os/VibratorTest.java +10 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,16 @@ public class VibratorTest { VibrationEffect.Composition.PRIMITIVE_QUICK_RISE}).length); } @Test public void getPrimitivesDurations_returnsArrayOfSameSize() { assertEquals(0, mVibratorSpy.getPrimitiveDurations(new int[0]).length); assertEquals(1, mVibratorSpy.getPrimitiveDurations( new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK}).length); assertEquals(2, mVibratorSpy.getPrimitiveDurations( new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK, VibrationEffect.Composition.PRIMITIVE_QUICK_RISE}).length); } @Test public void vibrate_withAudioAttributes_createsVibrationAttributesWithSameUsage() { VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); Loading