summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/Vibrator.java22
-rw-r--r--core/java/android/os/VibratorInfo.java39
-rw-r--r--core/tests/coretests/src/android/os/VibratorInfoTest.java181
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorController.java121
-rw-r--r--services/core/jni/com_android_server_vibrator_VibratorController.cpp69
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java20
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java4
7 files changed, 326 insertions, 130 deletions
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index b003d238c268..b90d438ffb93 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -208,6 +208,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.
*
* @param alwaysOnId The board-specific always-on ID to configure.
diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java
index 50d2de3da965..3121b952281e 100644
--- a/core/java/android/os/VibratorInfo.java
+++ b/core/java/android/os/VibratorInfo.java
@@ -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)) {
diff --git a/core/tests/coretests/src/android/os/VibratorInfoTest.java b/core/tests/coretests/src/android/os/VibratorInfoTest.java
index c06405affc1b..09c36dd261bd 100644
--- a/core/tests/coretests/src/android/os/VibratorInfoTest.java
+++ b/core/tests/coretests/src/android/os/VibratorInfoTest.java
@@ -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}));
-
- 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)));
+ assertEquals(complete, completeBuilder.build());
+
+ 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);
+ }
}
}
diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
index eaba083c551c..e3dc70b41c0d 100644
--- a/services/core/java/com/android/server/vibrator/VibratorController.java
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -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);
}
}
}
diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
index ef2d0baff031..f60b35499013 100644
--- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp
+++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
@@ -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));
}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
index 2a3c2c46ce4e..b54b6969e7df 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
@@ -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.
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index a28d18fb74d3..ce6639c6b4aa 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -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