diff options
4 files changed, 55 insertions, 12 deletions
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java index fe9e8c67e566..da0ed54e003e 100644 --- a/core/java/android/os/VibrationEffect.java +++ b/core/java/android/os/VibrationEffect.java @@ -149,14 +149,43 @@ public abstract class VibrationEffect implements Parcelable { * provide a better experience than you could otherwise build using the generic building * blocks. * + * This will fallback to a generic pattern if one exists and there does not exist a + * hardware-specific implementation of the effect. + * * @param effectId The ID of the effect to perform: - * {@link #EFFECT_CLICK}, {@link #EFFECT_DOUBLE_CLICK}. + * {@link #EFFECT_CLICK}, {@link #EFFECT_DOUBLE_CLICK}, {@link #EFFECT_TICK} * * @return The desired effect. * @hide */ public static VibrationEffect get(int effectId) { - VibrationEffect effect = new Prebaked(effectId); + return get(effectId, true); + } + + /** + * Get a predefined vibration effect. + * + * Predefined effects are a set of common vibration effects that should be identical, regardless + * of the app they come from, in order to provide a cohesive experience for users across + * the entire device. They also may be custom tailored to the device hardware in order to + * provide a better experience than you could otherwise build using the generic building + * blocks. + * + * Some effects you may only want to play if there's a hardware specific implementation because + * they may, for example, be too disruptive to the user without tuning. The {@code fallback} + * parameter allows you to decide whether you want to fallback to the generic implementation or + * only play if there's a tuned, hardware specific one available. + * + * @param effectId The ID of the effect to perform: + * {@link #EFFECT_CLICK}, {@link #EFFECT_DOUBLE_CLICK}, {@link #EFFECT_TICK} + * @param fallback Whether to fallback to a generic pattern if a hardware specific + * implementation doesn't exist. + * + * @return The desired effect. + * @hide + */ + public static VibrationEffect get(int effectId, boolean fallback) { + VibrationEffect effect = new Prebaked(effectId, fallback); effect.validate(); return effect; } @@ -374,19 +403,29 @@ public abstract class VibrationEffect implements Parcelable { /** @hide */ public static class Prebaked extends VibrationEffect implements Parcelable { private int mEffectId; + private boolean mFallback; public Prebaked(Parcel in) { - this(in.readInt()); + this(in.readInt(), in.readByte() != 0); } - public Prebaked(int effectId) { + public Prebaked(int effectId, boolean fallback) { mEffectId = effectId; + mFallback = fallback; } public int getId() { return mEffectId; } + /** + * Whether the effect should fall back to a generic pattern if there's no hardware specific + * implementation of it. + */ + public boolean shouldFallback() { + return mFallback; + } + @Override public void validate() { switch (mEffectId) { @@ -406,7 +445,7 @@ public abstract class VibrationEffect implements Parcelable { return false; } VibrationEffect.Prebaked other = (VibrationEffect.Prebaked) o; - return mEffectId == other.mEffectId; + return mEffectId == other.mEffectId && mFallback == other.mFallback; } @Override @@ -416,7 +455,7 @@ public abstract class VibrationEffect implements Parcelable { @Override public String toString() { - return "Prebaked{mEffectId=" + mEffectId + "}"; + return "Prebaked{mEffectId=" + mEffectId + ", mFallback=" + mFallback + "}"; } @@ -424,6 +463,7 @@ public abstract class VibrationEffect implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeInt(PARCEL_TOKEN_EFFECT); out.writeInt(mEffectId); + out.writeByte((byte) (mFallback ? 1 : 0)); } public static final Parcelable.Creator<Prebaked> CREATOR = diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 473384081656..046eb761d1c0 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -728,6 +728,9 @@ public class VibratorService extends IVibratorService.Stub return timeout; } } + if (!prebaked.shouldFallback()) { + return 0; + } final int id = prebaked.getId(); if (id < 0 || id >= mFallbackEffects.length || mFallbackEffects[id] == null) { Slog.w(TAG, "Failed to play prebaked effect, no fallback"); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index d21100c0cf72..68913c3a887a 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -7820,13 +7820,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { case HapticFeedbackConstants.VIRTUAL_KEY: return VibrationEffect.get(VibrationEffect.EFFECT_CLICK); case HapticFeedbackConstants.VIRTUAL_KEY_RELEASE: - return VibrationEffect.get(VibrationEffect.EFFECT_TICK); + return VibrationEffect.get(VibrationEffect.EFFECT_TICK, false); case HapticFeedbackConstants.KEYBOARD_PRESS: // == HapticFeedbackConstants.KEYBOARD_TAP return VibrationEffect.get(VibrationEffect.EFFECT_CLICK); case HapticFeedbackConstants.KEYBOARD_RELEASE: - return VibrationEffect.get(VibrationEffect.EFFECT_TICK); + return VibrationEffect.get(VibrationEffect.EFFECT_TICK, false); case HapticFeedbackConstants.TEXT_HANDLE_MOVE: - return VibrationEffect.get(VibrationEffect.EFFECT_TICK); + return VibrationEffect.get(VibrationEffect.EFFECT_TICK, false); default: return null; } diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index 0370490668ec..d2f374dd9e08 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -153,9 +153,9 @@ static jlong vibratorPerformEffect(JNIEnv*, jobject, jlong effect, jint strength if (status == Status::OK) { return lengthMs; } else if (status != Status::UNSUPPORTED_OPERATION) { - // Don't warn on UNSUPPORTED_OPERATION, that's a normal even and just means the motor - // doesn't have a pre-defined waveform to perform for it, so we should just fall back - // to the framework waveforms. + // Don't warn on UNSUPPORTED_OPERATION, that's a normal event and just means the motor + // doesn't have a pre-defined waveform to perform for it, so we should just give the + // opportunity to fall back to the framework waveforms. ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32 ", error=%" PRIu32 ").", static_cast<int64_t>(effect), static_cast<int32_t>(strength), static_cast<uint32_t>(status)); |