diff options
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 |