Merge "Add resonant frequency and Q factor to VibratorInfo" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
75eb6d7643
@@ -207,6 +207,28 @@ public abstract class Vibrator {
|
||||
*/
|
||||
public abstract boolean hasAmplitudeControl();
|
||||
|
||||
/**
|
||||
* Gets the resonant frequency of the vibrator.
|
||||
*
|
||||
* @return the resonant frequency of the vibrator, or {@link Float#NaN NaN} if it's unknown or
|
||||
* this vibrator is a composite of multiple physical devices.
|
||||
* @hide
|
||||
*/
|
||||
public float getResonantFrequency() {
|
||||
return Float.NaN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <a href="https://en.wikipedia.org/wiki/Q_factor">Q factor</a> of the vibrator.
|
||||
*
|
||||
* @return the Q factor of the vibrator, or {@link Float#NaN NaN} if it's unknown or
|
||||
* this vibrator is a composite of multiple physical devices.
|
||||
* @hide
|
||||
*/
|
||||
public float getQFactor() {
|
||||
return Float.NaN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure an always-on haptics effect.
|
||||
*
|
||||
|
||||
@@ -42,21 +42,27 @@ public final class VibratorInfo implements Parcelable {
|
||||
private final SparseBooleanArray mSupportedEffects;
|
||||
@Nullable
|
||||
private final SparseBooleanArray mSupportedPrimitives;
|
||||
private final float mResonantFrequency;
|
||||
private final float mQFactor;
|
||||
|
||||
VibratorInfo(Parcel in) {
|
||||
mId = in.readInt();
|
||||
mCapabilities = in.readLong();
|
||||
mSupportedEffects = in.readSparseBooleanArray();
|
||||
mSupportedPrimitives = in.readSparseBooleanArray();
|
||||
mResonantFrequency = in.readFloat();
|
||||
mQFactor = in.readFloat();
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public VibratorInfo(int id, long capabilities, int[] supportedEffects,
|
||||
int[] supportedPrimitives) {
|
||||
int[] supportedPrimitives, float resonantFrequency, float qFactor) {
|
||||
mId = id;
|
||||
mCapabilities = capabilities;
|
||||
mSupportedEffects = toSparseBooleanArray(supportedEffects);
|
||||
mSupportedPrimitives = toSparseBooleanArray(supportedPrimitives);
|
||||
mResonantFrequency = resonantFrequency;
|
||||
mQFactor = qFactor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,6 +71,8 @@ public final class VibratorInfo implements Parcelable {
|
||||
dest.writeLong(mCapabilities);
|
||||
dest.writeSparseBooleanArray(mSupportedEffects);
|
||||
dest.writeSparseBooleanArray(mSupportedPrimitives);
|
||||
dest.writeFloat(mResonantFrequency);
|
||||
dest.writeFloat(mQFactor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,12 +91,15 @@ public final class VibratorInfo implements Parcelable {
|
||||
VibratorInfo that = (VibratorInfo) o;
|
||||
return mId == that.mId && mCapabilities == that.mCapabilities
|
||||
&& Objects.equals(mSupportedEffects, that.mSupportedEffects)
|
||||
&& Objects.equals(mSupportedPrimitives, that.mSupportedPrimitives);
|
||||
&& Objects.equals(mSupportedPrimitives, that.mSupportedPrimitives)
|
||||
&& Objects.equals(mResonantFrequency, that.mResonantFrequency)
|
||||
&& Objects.equals(mQFactor, that.mQFactor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedPrimitives);
|
||||
return Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedPrimitives,
|
||||
mResonantFrequency, mQFactor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -99,6 +110,8 @@ public final class VibratorInfo implements Parcelable {
|
||||
+ ", mCapabilities flags=" + Long.toBinaryString(mCapabilities)
|
||||
+ ", mSupportedEffects=" + Arrays.toString(getSupportedEffectsNames())
|
||||
+ ", mSupportedPrimitives=" + Arrays.toString(getSupportedPrimitivesNames())
|
||||
+ ", mResonantFrequency=" + mResonantFrequency
|
||||
+ ", mQFactor=" + mQFactor
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@@ -156,6 +169,26 @@ public final class VibratorInfo implements Parcelable {
|
||||
return (mCapabilities & capability) == capability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the resonant frequency of the vibrator.
|
||||
*
|
||||
* @return the resonant frequency of the vibrator, or {@link Float#NaN NaN} if it's unknown or
|
||||
* this vibrator is a composite of multiple physical devices.
|
||||
*/
|
||||
public float getResonantFrequency() {
|
||||
return mResonantFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <a href="https://en.wikipedia.org/wiki/Q_factor">Q factor</a> of the vibrator.
|
||||
*
|
||||
* @return the Q factor of the vibrator, or {@link Float#NaN NaN} if it's unknown or
|
||||
* this vibrator is a composite of multiple physical devices.
|
||||
*/
|
||||
public float getQFactor() {
|
||||
return mQFactor;
|
||||
}
|
||||
|
||||
private String[] getCapabilitiesNames() {
|
||||
List<String> names = new ArrayList<>();
|
||||
if (hasCapability(IVibrator.CAP_ON_CALLBACK)) {
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
|
||||
package android.os;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.hardware.vibrator.IVibrator;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
@@ -33,72 +34,128 @@ public class VibratorInfoTest {
|
||||
|
||||
@Test
|
||||
public void testHasAmplitudeControl() {
|
||||
assertFalse(createInfo(/* capabilities= */ 0).hasAmplitudeControl());
|
||||
assertTrue(createInfo(IVibrator.CAP_COMPOSE_EFFECTS
|
||||
| IVibrator.CAP_AMPLITUDE_CONTROL).hasAmplitudeControl());
|
||||
VibratorInfo noCapabilities = new InfoBuilder().build();
|
||||
assertFalse(noCapabilities.hasAmplitudeControl());
|
||||
VibratorInfo composeAndAmplitudeControl = new InfoBuilder()
|
||||
.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS
|
||||
| IVibrator.CAP_AMPLITUDE_CONTROL)
|
||||
.build();
|
||||
assertTrue(composeAndAmplitudeControl.hasAmplitudeControl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasCapabilities() {
|
||||
assertTrue(createInfo(IVibrator.CAP_COMPOSE_EFFECTS)
|
||||
.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS));
|
||||
assertFalse(createInfo(IVibrator.CAP_COMPOSE_EFFECTS)
|
||||
.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL));
|
||||
VibratorInfo info = new InfoBuilder()
|
||||
.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
|
||||
.build();
|
||||
assertTrue(info.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS));
|
||||
assertFalse(info.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsEffectSupported() {
|
||||
VibratorInfo info = new VibratorInfo(/* id= */ 0, /* capabilities= */0,
|
||||
new int[]{VibrationEffect.EFFECT_CLICK}, null);
|
||||
VibratorInfo noEffects = new InfoBuilder().build();
|
||||
VibratorInfo canClick = new InfoBuilder()
|
||||
.setSupportedEffects(VibrationEffect.EFFECT_CLICK)
|
||||
.build();
|
||||
assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN,
|
||||
createInfo(/* capabilities= */ 0).isEffectSupported(VibrationEffect.EFFECT_CLICK));
|
||||
noEffects.isEffectSupported(VibrationEffect.EFFECT_CLICK));
|
||||
assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_YES,
|
||||
info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
|
||||
canClick.isEffectSupported(VibrationEffect.EFFECT_CLICK));
|
||||
assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_NO,
|
||||
info.isEffectSupported(VibrationEffect.EFFECT_TICK));
|
||||
canClick.isEffectSupported(VibrationEffect.EFFECT_TICK));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsPrimitiveSupported() {
|
||||
VibratorInfo info = new VibratorInfo(/* id= */ 0, IVibrator.CAP_COMPOSE_EFFECTS,
|
||||
null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
|
||||
VibratorInfo info = new InfoBuilder()
|
||||
.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
|
||||
.setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK)
|
||||
.build();
|
||||
assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
|
||||
assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_TICK));
|
||||
|
||||
// Returns false when there is no compose capability.
|
||||
info = new VibratorInfo(/* id= */ 0, /* capabilities= */ 0,
|
||||
null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
|
||||
info = new InfoBuilder()
|
||||
.setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK)
|
||||
.build();
|
||||
assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
VibratorInfo empty = new VibratorInfo(1, 0, null, null);
|
||||
VibratorInfo complete = new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
|
||||
new int[]{VibrationEffect.EFFECT_CLICK},
|
||||
new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
|
||||
InfoBuilder completeBuilder = new InfoBuilder()
|
||||
.setId(1)
|
||||
.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL)
|
||||
.setSupportedEffects(VibrationEffect.EFFECT_CLICK)
|
||||
.setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK)
|
||||
.setQFactor(2f)
|
||||
.setResonantFrequency(150f);
|
||||
VibratorInfo complete = completeBuilder.build();
|
||||
|
||||
assertEquals(complete, complete);
|
||||
assertEquals(complete, new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
|
||||
new int[]{VibrationEffect.EFFECT_CLICK},
|
||||
new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK}));
|
||||
assertEquals(complete, completeBuilder.build());
|
||||
|
||||
assertFalse(empty.equals(new VibratorInfo(1, 0, new int[]{}, new int[]{})));
|
||||
assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_COMPOSE_EFFECTS,
|
||||
new int[]{VibrationEffect.EFFECT_CLICK},
|
||||
new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK})));
|
||||
assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
|
||||
new int[]{}, new int[]{})));
|
||||
assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
|
||||
null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK})));
|
||||
assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
|
||||
new int[]{VibrationEffect.EFFECT_CLICK}, null)));
|
||||
VibratorInfo completeWithComposeControl = completeBuilder
|
||||
.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
|
||||
.build();
|
||||
assertNotEquals(complete, completeWithComposeControl);
|
||||
|
||||
VibratorInfo completeWithNoEffects = completeBuilder
|
||||
.setSupportedEffects()
|
||||
.setSupportedPrimitives()
|
||||
.build();
|
||||
assertNotEquals(complete, completeWithNoEffects);
|
||||
|
||||
VibratorInfo completeWithUnknownEffects = completeBuilder
|
||||
.setSupportedEffects(null)
|
||||
.build();
|
||||
assertNotEquals(complete, completeWithNoEffects);
|
||||
|
||||
VibratorInfo completeWithUnknownPrimitives = completeBuilder
|
||||
.setSupportedPrimitives(null)
|
||||
.build();
|
||||
assertNotEquals(complete, completeWithUnknownPrimitives);
|
||||
|
||||
VibratorInfo completeWithDifferentF0 = completeBuilder
|
||||
.setResonantFrequency(complete.getResonantFrequency() + 3f)
|
||||
.build();
|
||||
assertNotEquals(complete, completeWithDifferentF0);
|
||||
|
||||
VibratorInfo completeWithUnknownF0 = completeBuilder
|
||||
.setResonantFrequency(Float.NaN)
|
||||
.build();
|
||||
assertNotEquals(complete, completeWithUnknownF0);
|
||||
|
||||
VibratorInfo completeWithUnknownQFactor = completeBuilder
|
||||
.setQFactor(Float.NaN)
|
||||
.build();
|
||||
assertNotEquals(complete, completeWithUnknownQFactor);
|
||||
|
||||
VibratorInfo completeWithDifferentQFactor = completeBuilder
|
||||
.setQFactor(complete.getQFactor() + 3f)
|
||||
.build();
|
||||
assertNotEquals(complete, completeWithDifferentQFactor);
|
||||
|
||||
VibratorInfo empty = new InfoBuilder().setId(1).build();
|
||||
VibratorInfo emptyWithKnownSupport = new InfoBuilder()
|
||||
.setId(1)
|
||||
.setSupportedEffects()
|
||||
.setSupportedPrimitives()
|
||||
.build();
|
||||
assertNotEquals(empty, emptyWithKnownSupport);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerialization() {
|
||||
VibratorInfo original = new VibratorInfo(1, IVibrator.CAP_COMPOSE_EFFECTS,
|
||||
new int[]{VibrationEffect.EFFECT_CLICK}, null);
|
||||
public void testParceling() {
|
||||
VibratorInfo original = new InfoBuilder()
|
||||
.setId(1)
|
||||
.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
|
||||
.setSupportedEffects(VibrationEffect.EFFECT_CLICK)
|
||||
.setSupportedPrimitives(null)
|
||||
.setResonantFrequency(1.3f)
|
||||
.setQFactor(Float.NaN)
|
||||
.build();
|
||||
|
||||
Parcel parcel = Parcel.obtain();
|
||||
original.writeToParcel(parcel, 0);
|
||||
@@ -107,7 +164,47 @@ public class VibratorInfoTest {
|
||||
assertEquals(original, restored);
|
||||
}
|
||||
|
||||
private static VibratorInfo createInfo(long capabilities) {
|
||||
return new VibratorInfo(/* id= */ 0, capabilities, null, null);
|
||||
private static class InfoBuilder {
|
||||
private int mId = 0;
|
||||
private int mCapabilities = 0;
|
||||
private int[] mSupportedEffects = null;
|
||||
private int[] mSupportedPrimitives = null;
|
||||
private float mResonantFrequency = Float.NaN;
|
||||
private float mQFactor = Float.NaN;
|
||||
|
||||
public InfoBuilder setId(int id) {
|
||||
mId = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InfoBuilder setCapabilities(int capabilities) {
|
||||
mCapabilities = capabilities;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InfoBuilder setSupportedEffects(int... supportedEffects) {
|
||||
mSupportedEffects = supportedEffects;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InfoBuilder setSupportedPrimitives(int... supportedPrimitives) {
|
||||
mSupportedPrimitives = supportedPrimitives;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InfoBuilder setResonantFrequency(float resonantFrequency) {
|
||||
mResonantFrequency = resonantFrequency;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InfoBuilder setQFactor(float qFactor) {
|
||||
mQFactor = qFactor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public VibratorInfo build() {
|
||||
return new VibratorInfo(mId, mCapabilities, mSupportedEffects, mSupportedPrimitives,
|
||||
mResonantFrequency, mQFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,50 +54,6 @@ final class VibratorController {
|
||||
void onComplete(int vibratorId, long vibrationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the native part of this controller, creating a global reference to given
|
||||
* {@link OnVibrationCompleteListener} and returns a newly allocated native pointer. This
|
||||
* wrapper is responsible for deleting this pointer by calling the method pointed
|
||||
* by {@link #vibratorGetFinalizer()}.
|
||||
*
|
||||
* <p><b>Note:</b> Make sure the given implementation of {@link OnVibrationCompleteListener}
|
||||
* do not hold any strong reference to the instance responsible for deleting the returned
|
||||
* pointer, to avoid creating a cyclic GC root reference.
|
||||
*/
|
||||
static native long vibratorInit(int vibratorId, OnVibrationCompleteListener listener);
|
||||
|
||||
/**
|
||||
* Returns pointer to native function responsible for cleaning up the native pointer allocated
|
||||
* and returned by {@link #vibratorInit(int, OnVibrationCompleteListener)}.
|
||||
*/
|
||||
static native long vibratorGetFinalizer();
|
||||
|
||||
static native boolean vibratorIsAvailable(long nativePtr);
|
||||
|
||||
static native void vibratorOn(long nativePtr, long milliseconds, long vibrationId);
|
||||
|
||||
static native void vibratorOff(long nativePtr);
|
||||
|
||||
static native void vibratorSetAmplitude(long nativePtr, int amplitude);
|
||||
|
||||
static native int[] vibratorGetSupportedEffects(long nativePtr);
|
||||
|
||||
static native int[] vibratorGetSupportedPrimitives(long nativePtr);
|
||||
|
||||
static native long vibratorPerformEffect(
|
||||
long nativePtr, long effect, long strength, long vibrationId);
|
||||
|
||||
static native long vibratorPerformComposedEffect(
|
||||
long nativePtr, VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId);
|
||||
|
||||
static native void vibratorSetExternalControl(long nativePtr, boolean enabled);
|
||||
|
||||
static native long vibratorGetCapabilities(long nativePtr);
|
||||
|
||||
static native void vibratorAlwaysOnEnable(long nativePtr, long id, long effect, long strength);
|
||||
|
||||
static native void vibratorAlwaysOnDisable(long nativePtr, long id);
|
||||
|
||||
VibratorController(int vibratorId, OnVibrationCompleteListener listener) {
|
||||
this(vibratorId, listener, new NativeWrapper());
|
||||
}
|
||||
@@ -109,7 +65,8 @@ final class VibratorController {
|
||||
mNativeWrapper.init(vibratorId, listener);
|
||||
|
||||
mVibratorInfo = new VibratorInfo(vibratorId, nativeWrapper.getCapabilities(),
|
||||
nativeWrapper.getSupportedEffects(), nativeWrapper.getSupportedPrimitives());
|
||||
nativeWrapper.getSupportedEffects(), nativeWrapper.getSupportedPrimitives(),
|
||||
nativeWrapper.getResonantFrequency(), nativeWrapper.getQFactor());
|
||||
}
|
||||
|
||||
/** Register state listener for this vibrator. */
|
||||
@@ -336,13 +293,47 @@ final class VibratorController {
|
||||
/** Wrapper around the static-native methods of {@link VibratorController} for tests. */
|
||||
@VisibleForTesting
|
||||
public static class NativeWrapper {
|
||||
/**
|
||||
* Initializes the native part of this controller, creating a global reference to given
|
||||
* {@link OnVibrationCompleteListener} and returns a newly allocated native pointer. This
|
||||
* wrapper is responsible for deleting this pointer by calling the method pointed
|
||||
* by {@link #getNativeFinalizer()}.
|
||||
*
|
||||
* <p><b>Note:</b> Make sure the given implementation of {@link OnVibrationCompleteListener}
|
||||
* do not hold any strong reference to the instance responsible for deleting the returned
|
||||
* pointer, to avoid creating a cyclic GC root reference.
|
||||
*/
|
||||
private static native long nativeInit(int vibratorId, OnVibrationCompleteListener listener);
|
||||
|
||||
/**
|
||||
* Returns pointer to native function responsible for cleaning up the native pointer
|
||||
* allocated and returned by {@link #nativeInit(int, OnVibrationCompleteListener)}.
|
||||
*/
|
||||
private static native long getNativeFinalizer();
|
||||
private static native boolean isAvailable(long nativePtr);
|
||||
private static native void on(long nativePtr, long milliseconds, long vibrationId);
|
||||
private static native void off(long nativePtr);
|
||||
private static native void setAmplitude(long nativePtr, int amplitude);
|
||||
private static native int[] getSupportedEffects(long nativePtr);
|
||||
private static native int[] getSupportedPrimitives(long nativePtr);
|
||||
private static native long performEffect(
|
||||
long nativePtr, long effect, long strength, long vibrationId);
|
||||
private static native long performComposedEffect(long nativePtr,
|
||||
VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId);
|
||||
private static native void setExternalControl(long nativePtr, boolean enabled);
|
||||
private static native long getCapabilities(long nativePtr);
|
||||
private static native void alwaysOnEnable(long nativePtr, long id, long effect,
|
||||
long strength);
|
||||
private static native void alwaysOnDisable(long nativePtr, long id);
|
||||
private static native float getResonantFrequency(long nativePtr);
|
||||
private static native float getQFactor(long nativePtr);
|
||||
|
||||
private long mNativePtr = 0;
|
||||
|
||||
/** Initializes native controller and allocation registry to destroy native instances. */
|
||||
public void init(int vibratorId, OnVibrationCompleteListener listener) {
|
||||
mNativePtr = VibratorController.vibratorInit(vibratorId, listener);
|
||||
long finalizerPtr = VibratorController.vibratorGetFinalizer();
|
||||
mNativePtr = nativeInit(vibratorId, listener);
|
||||
long finalizerPtr = getNativeFinalizer();
|
||||
|
||||
if (finalizerPtr != 0) {
|
||||
NativeAllocationRegistry registry =
|
||||
@@ -354,65 +345,73 @@ final class VibratorController {
|
||||
|
||||
/** Check if the vibrator is currently available. */
|
||||
public boolean isAvailable() {
|
||||
return VibratorController.vibratorIsAvailable(mNativePtr);
|
||||
return isAvailable(mNativePtr);
|
||||
}
|
||||
|
||||
/** Turns vibrator on for given time. */
|
||||
public void on(long milliseconds, long vibrationId) {
|
||||
VibratorController.vibratorOn(mNativePtr, milliseconds, vibrationId);
|
||||
on(mNativePtr, milliseconds, vibrationId);
|
||||
}
|
||||
|
||||
/** Turns vibrator off. */
|
||||
public void off() {
|
||||
VibratorController.vibratorOff(mNativePtr);
|
||||
off(mNativePtr);
|
||||
}
|
||||
|
||||
/** Sets the amplitude for the vibrator to run. */
|
||||
public void setAmplitude(int amplitude) {
|
||||
VibratorController.vibratorSetAmplitude(mNativePtr, amplitude);
|
||||
setAmplitude(mNativePtr, amplitude);
|
||||
}
|
||||
|
||||
/** Returns all predefined effects supported by the device vibrator. */
|
||||
public int[] getSupportedEffects() {
|
||||
return VibratorController.vibratorGetSupportedEffects(mNativePtr);
|
||||
return getSupportedEffects(mNativePtr);
|
||||
}
|
||||
|
||||
/** Returns all compose primitives supported by the device vibrator. */
|
||||
public int[] getSupportedPrimitives() {
|
||||
return VibratorController.vibratorGetSupportedPrimitives(mNativePtr);
|
||||
return getSupportedPrimitives(mNativePtr);
|
||||
}
|
||||
|
||||
/** Turns vibrator on to perform one of the supported effects. */
|
||||
public long perform(long effect, long strength, long vibrationId) {
|
||||
return VibratorController.vibratorPerformEffect(
|
||||
mNativePtr, effect, strength, vibrationId);
|
||||
return performEffect(mNativePtr, effect, strength, vibrationId);
|
||||
}
|
||||
|
||||
/** Turns vibrator on to perform one of the supported composed effects. */
|
||||
public long compose(
|
||||
VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId) {
|
||||
return VibratorController.vibratorPerformComposedEffect(mNativePtr, effect,
|
||||
vibrationId);
|
||||
return performComposedEffect(mNativePtr, effect, vibrationId);
|
||||
}
|
||||
|
||||
/** Enabled the device vibrator to be controlled by another service. */
|
||||
public void setExternalControl(boolean enabled) {
|
||||
VibratorController.vibratorSetExternalControl(mNativePtr, enabled);
|
||||
setExternalControl(mNativePtr, enabled);
|
||||
}
|
||||
|
||||
/** Returns all capabilities of the device vibrator. */
|
||||
public long getCapabilities() {
|
||||
return VibratorController.vibratorGetCapabilities(mNativePtr);
|
||||
return getCapabilities(mNativePtr);
|
||||
}
|
||||
|
||||
/** Enable always-on vibration with given id and effect. */
|
||||
public void alwaysOnEnable(long id, long effect, long strength) {
|
||||
VibratorController.vibratorAlwaysOnEnable(mNativePtr, id, effect, strength);
|
||||
alwaysOnEnable(mNativePtr, id, effect, strength);
|
||||
}
|
||||
|
||||
/** Disable always-on vibration for given id. */
|
||||
public void alwaysOnDisable(long id) {
|
||||
VibratorController.vibratorAlwaysOnDisable(mNativePtr, id);
|
||||
alwaysOnDisable(mNativePtr, id);
|
||||
}
|
||||
|
||||
/** Gets the vibrator's resonant frequency (F0) */
|
||||
public float getResonantFrequency() {
|
||||
return getResonantFrequency(mNativePtr);
|
||||
}
|
||||
|
||||
/** Gets the vibrator's Q factor */
|
||||
public float getQFactor() {
|
||||
return getQFactor(mNativePtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@
|
||||
#include "com_android_server_vibrator_VibratorManagerService.h"
|
||||
|
||||
namespace V1_0 = android::hardware::vibrator::V1_0;
|
||||
namespace V1_1 = android::hardware::vibrator::V1_1;
|
||||
namespace V1_2 = android::hardware::vibrator::V1_2;
|
||||
namespace V1_3 = android::hardware::vibrator::V1_3;
|
||||
namespace aidl = android::hardware::vibrator;
|
||||
|
||||
@@ -85,10 +83,11 @@ static std::shared_ptr<vibrator::HalController> findVibrator(int32_t vibratorId)
|
||||
class VibratorControllerWrapper {
|
||||
public:
|
||||
VibratorControllerWrapper(JNIEnv* env, int32_t vibratorId, jobject callbackListener)
|
||||
: mHal(std::move(findVibrator(vibratorId))),
|
||||
: mHal(findVibrator(vibratorId)),
|
||||
mVibratorId(vibratorId),
|
||||
mCallbackListener(env->NewGlobalRef(callbackListener)) {
|
||||
LOG_ALWAYS_FATAL_IF(mHal == nullptr, "Unable to find reference to vibrator hal");
|
||||
LOG_ALWAYS_FATAL_IF(mHal == nullptr,
|
||||
"Failed to connect to vibrator HAL, or vibratorId is invalid");
|
||||
LOG_ALWAYS_FATAL_IF(mCallbackListener == nullptr,
|
||||
"Unable to create global reference to vibration callback handler");
|
||||
}
|
||||
@@ -130,15 +129,15 @@ static void destroyNativeWrapper(void* ptr) {
|
||||
}
|
||||
}
|
||||
|
||||
static jlong vibratorInit(JNIEnv* env, jclass /* clazz */, jint vibratorId,
|
||||
jobject callbackListener) {
|
||||
static jlong vibratorNativeInit(JNIEnv* env, jclass /* clazz */, jint vibratorId,
|
||||
jobject callbackListener) {
|
||||
std::unique_ptr<VibratorControllerWrapper> wrapper =
|
||||
std::make_unique<VibratorControllerWrapper>(env, vibratorId, callbackListener);
|
||||
wrapper->hal()->init();
|
||||
return reinterpret_cast<jlong>(wrapper.release());
|
||||
}
|
||||
|
||||
static jlong vibratorGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
|
||||
static jlong vibratorGetNativeFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
|
||||
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeWrapper));
|
||||
}
|
||||
|
||||
@@ -286,25 +285,46 @@ static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong ptr,
|
||||
wrapper->hal()->alwaysOnDisable(static_cast<int32_t>(id));
|
||||
}
|
||||
|
||||
static float vibratorGetResonantFrequency(JNIEnv* env, jclass /* clazz */, jlong ptr) {
|
||||
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
|
||||
if (wrapper == nullptr) {
|
||||
ALOGE("vibratorGetResonantFrequency failed because native wrapper was not initialized");
|
||||
return NAN;
|
||||
}
|
||||
auto result = wrapper->hal()->getResonantFrequency();
|
||||
return result.isOk() ? static_cast<jfloat>(result.value()) : NAN;
|
||||
}
|
||||
|
||||
static float vibratorGetQFactor(JNIEnv* env, jclass /* clazz */, jlong ptr) {
|
||||
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
|
||||
if (wrapper == nullptr) {
|
||||
ALOGE("vibratorGetQFactor failed because native wrapper was not initialized");
|
||||
return NAN;
|
||||
}
|
||||
auto result = wrapper->hal()->getQFactor();
|
||||
return result.isOk() ? static_cast<jfloat>(result.value()) : NAN;
|
||||
}
|
||||
|
||||
static const JNINativeMethod method_table[] = {
|
||||
{"vibratorInit",
|
||||
{"nativeInit",
|
||||
"(ILcom/android/server/vibrator/VibratorController$OnVibrationCompleteListener;)J",
|
||||
(void*)vibratorInit},
|
||||
{"vibratorGetFinalizer", "()J", (void*)vibratorGetFinalizer},
|
||||
{"vibratorIsAvailable", "(J)Z", (void*)vibratorIsAvailable},
|
||||
{"vibratorOn", "(JJJ)V", (void*)vibratorOn},
|
||||
{"vibratorOff", "(J)V", (void*)vibratorOff},
|
||||
{"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude},
|
||||
{"vibratorPerformEffect", "(JJJJ)J", (void*)vibratorPerformEffect},
|
||||
{"vibratorPerformComposedEffect",
|
||||
"(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;J)J",
|
||||
(void*)vibratorNativeInit},
|
||||
{"getNativeFinalizer", "()J", (void*)vibratorGetNativeFinalizer},
|
||||
{"isAvailable", "(J)Z", (void*)vibratorIsAvailable},
|
||||
{"on", "(JJJ)V", (void*)vibratorOn},
|
||||
{"off", "(J)V", (void*)vibratorOff},
|
||||
{"setAmplitude", "(JI)V", (void*)vibratorSetAmplitude},
|
||||
{"performEffect", "(JJJJ)J", (void*)vibratorPerformEffect},
|
||||
{"performComposedEffect", "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;J)J",
|
||||
(void*)vibratorPerformComposedEffect},
|
||||
{"vibratorGetSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects},
|
||||
{"vibratorGetSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives},
|
||||
{"vibratorSetExternalControl", "(JZ)V", (void*)vibratorSetExternalControl},
|
||||
{"vibratorGetCapabilities", "(J)J", (void*)vibratorGetCapabilities},
|
||||
{"vibratorAlwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable},
|
||||
{"vibratorAlwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable},
|
||||
{"getSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects},
|
||||
{"getSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives},
|
||||
{"setExternalControl", "(JZ)V", (void*)vibratorSetExternalControl},
|
||||
{"getCapabilities", "(J)J", (void*)vibratorGetCapabilities},
|
||||
{"alwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable},
|
||||
{"alwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable},
|
||||
{"getResonantFrequency", "(J)F", (void*)vibratorGetResonantFrequency},
|
||||
{"getQFactor", "(J)F", (void*)vibratorGetQFactor},
|
||||
};
|
||||
|
||||
int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env) {
|
||||
@@ -320,7 +340,8 @@ int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env
|
||||
sPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F");
|
||||
sPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I");
|
||||
|
||||
return jniRegisterNativeMethods(env, "com/android/server/vibrator/VibratorController",
|
||||
return jniRegisterNativeMethods(env,
|
||||
"com/android/server/vibrator/VibratorController$NativeWrapper",
|
||||
method_table, NELEM(method_table));
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@ final class FakeVibratorControllerProvider {
|
||||
private int mCapabilities;
|
||||
private int[] mSupportedEffects;
|
||||
private int[] mSupportedPrimitives;
|
||||
private float mResonantFrequency;
|
||||
private float mQFactor;
|
||||
|
||||
private final class FakeNativeWrapper extends VibratorController.NativeWrapper {
|
||||
public int vibratorId;
|
||||
@@ -89,6 +91,14 @@ final class FakeVibratorControllerProvider {
|
||||
return mSupportedPrimitives;
|
||||
}
|
||||
|
||||
public float getResonantFrequency() {
|
||||
return mResonantFrequency;
|
||||
}
|
||||
|
||||
public float getQFactor() {
|
||||
return mQFactor;
|
||||
}
|
||||
|
||||
public long perform(long effect, long strength, long vibrationId) {
|
||||
if (mSupportedEffects == null
|
||||
|| Arrays.binarySearch(mSupportedEffects, (int) effect) < 0) {
|
||||
@@ -198,6 +208,16 @@ final class FakeVibratorControllerProvider {
|
||||
mSupportedPrimitives = primitives;
|
||||
}
|
||||
|
||||
/** Set the resonant frequency of the fake vibrator hardware. */
|
||||
public void setResonantFrequency(float resonantFrequency) {
|
||||
mResonantFrequency = resonantFrequency;
|
||||
}
|
||||
|
||||
/** Set the Q factor of the fake vibrator hardware. */
|
||||
public void setQFactor(float qFactor) {
|
||||
mQFactor = qFactor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the amplitudes set by this controller, including zeroes for each time the vibrator was
|
||||
* turned off.
|
||||
|
||||
@@ -266,6 +266,8 @@ public class VibratorManagerServiceTest {
|
||||
vibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS, IVibrator.CAP_AMPLITUDE_CONTROL);
|
||||
vibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
|
||||
vibrator.setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK);
|
||||
vibrator.setResonantFrequency(123.f);
|
||||
vibrator.setQFactor(Float.NaN);
|
||||
VibratorInfo info = createSystemReadyService().getVibratorInfo(1);
|
||||
|
||||
assertNotNull(info);
|
||||
@@ -279,6 +281,8 @@ public class VibratorManagerServiceTest {
|
||||
info.isEffectSupported(VibrationEffect.EFFECT_TICK));
|
||||
assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
|
||||
assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_TICK));
|
||||
assertEquals(123.f, info.getResonantFrequency(), 0.01 /*tolerance*/);
|
||||
assertTrue(Float.isNaN(info.getQFactor()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user