diff --git a/app/src/main/java/helium314/keyboard/latin/AppUpgrade.kt b/app/src/main/java/helium314/keyboard/latin/AppUpgrade.kt
index 1310c7baff..1ddc341676 100644
--- a/app/src/main/java/helium314/keyboard/latin/AppUpgrade.kt
+++ b/app/src/main/java/helium314/keyboard/latin/AppUpgrade.kt
@@ -2,6 +2,7 @@ package helium314.keyboard.latin
import android.annotation.SuppressLint
import android.content.Context
+import android.content.SharedPreferences
import androidx.core.content.edit
import helium314.keyboard.compat.isDeviceLocked
import helium314.keyboard.compat.isUserLocked
@@ -598,6 +599,19 @@ object AppUpgrade {
!prefs.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, Defaults.PREF_BIGRAM_PREDICTIONS))
}
}
+ if (prefs.contains(Settings.PREF_VIBRATE_ON)) {
+ prefs.edit {
+ if (prefs.getBoolean(Settings.PREF_VIBRATE_ON, false))
+ if (prefs.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, Defaults.PREF_VIBRATION_DURATION_SETTINGS) == -1) {
+ putString(Settings.PREF_VIBRATION_TYPE, AudioAndHapticFeedbackManager.VibrationType.SYSTEM.toString())
+ putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, Defaults.PREF_VIBRATION_DURATION_SETTINGS)
+ }
+ else
+ putString(Settings.PREF_VIBRATION_TYPE, AudioAndHapticFeedbackManager.VibrationType.CUSTOM.toString())
+ else putString(Settings.PREF_VIBRATION_TYPE, AudioAndHapticFeedbackManager.VibrationType.OFF.toString())
+ remove(Settings.PREF_VIBRATE_ON)
+ }
+ }
upgradeToolbarPrefs(prefs)
LayoutUtilsCustom.onLayoutFileChanged() // just to be sure
prefs.edit { putInt(Settings.PREF_VERSION_CODE, BuildConfig.VERSION_CODE) }
diff --git a/app/src/main/java/helium314/keyboard/latin/AudioAndHapticFeedbackManager.java b/app/src/main/java/helium314/keyboard/latin/AudioAndHapticFeedbackManager.java
index 9c1f6aa724..b932eb1e04 100644
--- a/app/src/main/java/helium314/keyboard/latin/AudioAndHapticFeedbackManager.java
+++ b/app/src/main/java/helium314/keyboard/latin/AudioAndHapticFeedbackManager.java
@@ -8,7 +8,10 @@
import android.content.Context;
import android.media.AudioManager;
+import android.os.Build;
+import android.os.VibrationEffect;
import android.os.Vibrator;
+import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.View;
@@ -38,6 +41,12 @@ public static AudioAndHapticFeedbackManager getInstance() {
return sInstance;
}
+ public enum VibrationType {
+ OFF,
+ SYSTEM,
+ CUSTOM;
+ }
+
private AudioAndHapticFeedbackManager() {
// Intentional empty constructor for singleton.
}
@@ -64,11 +73,14 @@ public boolean hasVibrator() {
return mVibrator != null && mVibrator.hasVibrator();
}
- public void vibrate(final long milliseconds) {
- if (mVibrator == null || milliseconds <= 0) {
+ public void vibrate(final long milliseconds, final int amplitude) {
+ if (mVibrator == null || milliseconds <= 0 || amplitude <= 0) {
return;
}
- mVibrator.vibrate(milliseconds);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ mVibrator.vibrate(VibrationEffect.createOneShot(milliseconds, amplitude));
+ } else
+ mVibrator.vibrate(milliseconds);
}
private boolean reevaluateIfSoundIsOn() {
@@ -99,22 +111,19 @@ public void performAudioFeedback(final int code, final HapticEvent hapticEvent)
}
public void performHapticFeedback(final View viewToPerformHapticFeedbackOn, final HapticEvent hapticEvent) {
- if (!mSettingsValues.mVibrateOn || (mDoNotDisturb && !mSettingsValues.mVibrateInDndMode)) {
+ if (mDoNotDisturb && !mSettingsValues.mVibrateInDndMode) {
return;
}
if (hapticEvent == HapticEvent.NO_HAPTICS) {
// Avoid surprises with the handling of HapticFeedbackConstants.NO_HAPTICS
return;
}
- if (hapticEvent.allowCustomDuration && mSettingsValues.mKeypressVibrationDuration >= 0) {
- vibrate(mSettingsValues.mKeypressVibrationDuration);
- return;
- }
- // Go ahead with the system default
- if (viewToPerformHapticFeedbackOn != null) {
+ if (mSettingsValues.mVibrationType == VibrationType.CUSTOM && hapticEvent.allowCustomDuration) {
+ vibrate(mSettingsValues.mKeypressVibrationDuration, mSettingsValues.mKeypressVibrationAmplitude);
+ } else if (mSettingsValues.mVibrationType != VibrationType.OFF && viewToPerformHapticFeedbackOn != null) {
viewToPerformHapticFeedbackOn.performHapticFeedback(
- hapticEvent.feedbackConstant,
- HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
+ hapticEvent.feedbackConstant,
+ HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
}
}
diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java
index cfc9b3603c..338a81901b 100644
--- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java
+++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java
@@ -1616,16 +1616,17 @@ public void hapticAndAudioFeedback(final int code, final int repeatCount,
}
// TODO: Use event time that the last feedback has been generated instead of relying on
// a repeat count to thin out feedback.
- if (repeatCount % PERIOD_FOR_AUDIO_AND_HAPTIC_FEEDBACK_IN_KEY_REPEAT == 0) {
- return;
- }
+
+// if (repeatCount % PERIOD_FOR_AUDIO_AND_HAPTIC_FEEDBACK_IN_KEY_REPEAT == 0) {
+// return;
+// }
}
final AudioAndHapticFeedbackManager feedbackManager =
AudioAndHapticFeedbackManager.getInstance();
- if (repeatCount == 0) {
+// if (repeatCount == 0) {
// TODO: Reconsider how to perform haptic feedback when repeating key.
feedbackManager.performHapticFeedback(keyboardView, hapticEvent);
- }
+// }
feedbackManager.performAudioFeedback(code, hapticEvent);
}
diff --git a/app/src/main/java/helium314/keyboard/latin/settings/Defaults.kt b/app/src/main/java/helium314/keyboard/latin/settings/Defaults.kt
index e036231c07..6dde33502d 100644
--- a/app/src/main/java/helium314/keyboard/latin/settings/Defaults.kt
+++ b/app/src/main/java/helium314/keyboard/latin/settings/Defaults.kt
@@ -6,6 +6,7 @@ import android.os.Build
import android.util.TypedValue
import android.view.Gravity
import helium314.keyboard.keyboard.KeyboardTheme
+import helium314.keyboard.latin.AudioAndHapticFeedbackManager
import helium314.keyboard.latin.BuildConfig
import helium314.keyboard.latin.common.Constants.Separators
import helium314.keyboard.latin.common.Constants.Subtype.ExtraValue
@@ -51,7 +52,8 @@ object Defaults {
const val PREF_CUSTOM_ICON_NAMES = ""
const val PREF_TOOLBAR_CUSTOM_KEY_CODES = ""
const val PREF_AUTO_CAP = true
- const val PREF_VIBRATE_ON = false
+ @JvmField
+ val PREF_VIBRATION_TYPE: String = AudioAndHapticFeedbackManager.VibrationType.OFF.toString()
const val PREF_VIBRATE_IN_DND_MODE = false
const val PREF_SOUND_ON = false
const val PREF_SUGGEST_EMOJIS = true
@@ -105,7 +107,8 @@ object Defaults {
const val PREF_SUGGEST_PUNCTUATION = false
const val PREF_SUGGEST_CLIPBOARD_CONTENT = true
const val PREF_GESTURE_INPUT = true
- const val PREF_VIBRATION_DURATION_SETTINGS = -1
+ const val PREF_VIBRATION_DURATION_SETTINGS = 1
+ const val PREF_VIBRATION_AMPLITUDE_SETTINGS = 128
const val PREF_KEYPRESS_SOUND_VOLUME = -0.01f
const val PREF_KEY_LONGPRESS_TIMEOUT = 300
const val PREF_ENABLE_EMOJI_ALT_PHYSICAL_KEY = true
diff --git a/app/src/main/java/helium314/keyboard/latin/settings/Settings.java b/app/src/main/java/helium314/keyboard/latin/settings/Settings.java
index ee8f57cf3b..d23c672d81 100644
--- a/app/src/main/java/helium314/keyboard/latin/settings/Settings.java
+++ b/app/src/main/java/helium314/keyboard/latin/settings/Settings.java
@@ -69,6 +69,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_AUTO_CAP = "auto_cap";
public static final String PREF_VIBRATE_ON = "vibrate_on";
+ public static final String PREF_VIBRATION_TYPE = "vibration_type";
public static final String PREF_VIBRATE_IN_DND_MODE = "vibrate_in_dnd_mode";
public static final String PREF_SOUND_ON = "sound_on";
public static final String PREF_SUGGEST_EMOJIS = "suggest_emojis";
@@ -116,6 +117,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_SUGGEST_CLIPBOARD_CONTENT = "suggest_clipboard_content";
public static final String PREF_GESTURE_INPUT = "gesture_input";
public static final String PREF_VIBRATION_DURATION_SETTINGS = "vibration_duration_settings";
+ public static final String PREF_VIBRATION_AMPLITUDE_SETTINGS = "vibration_amplitude_settings";
public static final String PREF_KEYPRESS_SOUND_VOLUME = "keypress_sound_volume";
public static final String PREF_KEY_LONGPRESS_TIMEOUT = "key_longpress_timeout";
public static final String PREF_ENABLE_EMOJI_ALT_PHYSICAL_KEY = "enable_emoji_alt_physical_key";
@@ -300,9 +302,11 @@ public static int readScreenMetrics(final Resources res) {
return res.getInteger(R.integer.config_screen_metrics);
}
- public static boolean readVibrationEnabled(final SharedPreferences prefs) {
- return prefs.getBoolean(PREF_VIBRATE_ON, Defaults.PREF_VIBRATE_ON)
- && AudioAndHapticFeedbackManager.getInstance().hasVibrator();
+ public static AudioAndHapticFeedbackManager.VibrationType readVibrationType(final SharedPreferences prefs) {
+ return AudioAndHapticFeedbackManager.getInstance().hasVibrator()
+ ? AudioAndHapticFeedbackManager.VibrationType.valueOf(
+ prefs.getString(PREF_VIBRATION_TYPE, Defaults.PREF_VIBRATION_TYPE))
+ : AudioAndHapticFeedbackManager.VibrationType.OFF;
}
public void toggleAutoCorrect() {
diff --git a/app/src/main/java/helium314/keyboard/latin/settings/SettingsValues.java b/app/src/main/java/helium314/keyboard/latin/settings/SettingsValues.java
index 6dcb79689f..096e71ea84 100644
--- a/app/src/main/java/helium314/keyboard/latin/settings/SettingsValues.java
+++ b/app/src/main/java/helium314/keyboard/latin/settings/SettingsValues.java
@@ -21,6 +21,7 @@
import helium314.keyboard.compat.ConfigurationCompatKt;
import helium314.keyboard.keyboard.KeyboardTheme;
import helium314.keyboard.keyboard.internal.keyboard_parser.LocaleKeyboardInfosKt;
+import helium314.keyboard.latin.AudioAndHapticFeedbackManager;
import helium314.keyboard.latin.InputAttributes;
import helium314.keyboard.latin.R;
import helium314.keyboard.latin.RichInputMethodManager;
@@ -51,7 +52,7 @@ public class SettingsValues {
public final int mDisplayOrientation;
// From preferences
public final boolean mAutoCap;
- public final boolean mVibrateOn;
+ public final AudioAndHapticFeedbackManager.VibrationType mVibrationType;
public final boolean mVibrateInDndMode;
public final boolean mSoundOn;
public final boolean mSuggestEmojis;
@@ -141,6 +142,7 @@ public class SettingsValues {
public final boolean mSuggestionStripHiddenPerUserSettings;
public final boolean mSecondaryStripVisible;
public final int mKeypressVibrationDuration;
+ public final int mKeypressVibrationAmplitude;
public final float mKeypressSoundVolume;
public final boolean mAutoCorrectionEnabledPerUserSettings;
public final boolean mAutoCorrectEnabled;
@@ -172,7 +174,7 @@ public SettingsValues(final Context context, final SharedPreferences prefs, fina
mToolbarMode = Settings.readToolbarMode(prefs);
mToolbarHidingGlobal = prefs.getBoolean(Settings.PREF_TOOLBAR_HIDING_GLOBAL, Defaults.PREF_TOOLBAR_HIDING_GLOBAL);
mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, Defaults.PREF_AUTO_CAP) && ScriptUtils.scriptSupportsUppercase(mLocale);
- mVibrateOn = Settings.readVibrationEnabled(prefs);
+ mVibrationType = Settings.readVibrationType(prefs);
mVibrateInDndMode = prefs.getBoolean(Settings.PREF_VIBRATE_IN_DND_MODE, Defaults.PREF_VIBRATE_IN_DND_MODE);
mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON, Defaults.PREF_SOUND_ON);
mSuggestEmojis = prefs.getBoolean(Settings.PREF_SUGGEST_EMOJIS, Defaults.PREF_SUGGEST_EMOJIS);
@@ -231,6 +233,7 @@ public SettingsValues(final Context context, final SharedPreferences prefs, fina
// Compute other readable settings
mKeyLongpressTimeout = prefs.getInt(Settings.PREF_KEY_LONGPRESS_TIMEOUT, Defaults.PREF_KEY_LONGPRESS_TIMEOUT);
mKeypressVibrationDuration = prefs.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, Defaults.PREF_VIBRATION_DURATION_SETTINGS);
+ mKeypressVibrationAmplitude = prefs.getInt(Settings.PREF_VIBRATION_AMPLITUDE_SETTINGS, Defaults.PREF_VIBRATION_AMPLITUDE_SETTINGS);
mKeypressSoundVolume = prefs.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, Defaults.PREF_KEYPRESS_SOUND_VOLUME);
mEnableEmojiAltPhysicalKey = prefs.getBoolean(Settings.PREF_ENABLE_EMOJI_ALT_PHYSICAL_KEY, Defaults.PREF_ENABLE_EMOJI_ALT_PHYSICAL_KEY);
mGestureInputEnabled = JniUtils.sHaveGestureLib && prefs.getBoolean(Settings.PREF_GESTURE_INPUT, Defaults.PREF_GESTURE_INPUT);
@@ -384,8 +387,8 @@ public String dump() {
sb.append("" + mSpacingAndPunctuations.dump());
sb.append("\n mAutoCap = ");
sb.append("" + mAutoCap);
- sb.append("\n mVibrateOn = ");
- sb.append("" + mVibrateOn);
+ sb.append("\n mVibrationType = ");
+ sb.append("" + mVibrationType);
sb.append("\n mSoundOn = ");
sb.append("" + mSoundOn);
sb.append("\n mKeyPreviewPopupOn = ");
@@ -420,6 +423,8 @@ public String dump() {
sb.append("" + mInputAttributes);
sb.append("\n mKeypressVibrationDuration = ");
sb.append("" + mKeypressVibrationDuration);
+ sb.append("\n mKeypressVibrationAmplitude = ");
+ sb.append("" + mKeypressVibrationAmplitude);
sb.append("\n mKeypressSoundVolume = ");
sb.append("" + mKeypressSoundVolume);
sb.append("\n mAutoCorrectEnabled = ");
diff --git a/app/src/main/java/helium314/keyboard/settings/screens/PreferencesScreen.kt b/app/src/main/java/helium314/keyboard/settings/screens/PreferencesScreen.kt
index 544c32ef31..995aca0a03 100644
--- a/app/src/main/java/helium314/keyboard/settings/screens/PreferencesScreen.kt
+++ b/app/src/main/java/helium314/keyboard/settings/screens/PreferencesScreen.kt
@@ -3,6 +3,7 @@ package helium314.keyboard.settings.screens
import android.content.Context
import android.media.AudioManager
+import android.os.Build
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
@@ -42,6 +43,7 @@ fun PreferencesScreen(
if ((b?.value ?: 0) < 0)
Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
val clipboardHistoryEnabled = prefs.getBoolean(Settings.PREF_ENABLE_CLIPBOARD_HISTORY, Defaults.PREF_ENABLE_CLIPBOARD_HISTORY)
+ val vibrationType = Settings.readVibrationType(prefs);
val items = listOf(
R.string.settings_category_input,
Settings.PREF_SHOW_HINTS,
@@ -52,10 +54,13 @@ fun PreferencesScreen(
Settings.PREF_SHOW_TLD_POPUP_KEYS,
Settings.PREF_POPUP_ON,
if (AudioAndHapticFeedbackManager.getInstance().hasVibrator())
- Settings.PREF_VIBRATE_ON else null,
- if (prefs.getBoolean(Settings.PREF_VIBRATE_ON, Defaults.PREF_VIBRATE_ON))
+ Settings.PREF_VIBRATION_TYPE else null,
+ if (vibrationType == AudioAndHapticFeedbackManager.VibrationType.CUSTOM)
Settings.PREF_VIBRATION_DURATION_SETTINGS else null,
- if (prefs.getBoolean(Settings.PREF_VIBRATE_ON, Defaults.PREF_VIBRATE_ON))
+ if (vibrationType == AudioAndHapticFeedbackManager.VibrationType.CUSTOM &&
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
+ Settings.PREF_VIBRATION_AMPLITUDE_SETTINGS else null,
+ if (vibrationType != AudioAndHapticFeedbackManager.VibrationType.OFF)
Settings.PREF_VIBRATE_IN_DND_MODE else null,
Settings.PREF_SOUND_ON,
if (prefs.getBoolean(Settings.PREF_SOUND_ON, Defaults.PREF_SOUND_ON))
@@ -112,8 +117,16 @@ fun createPreferencesSettings(context: Context) = listOf(
Setting(context, Settings.PREF_POPUP_ON, R.string.popup_on_keypress) {
SwitchPreference(it, Defaults.PREF_POPUP_ON) { KeyboardSwitcher.getInstance().reloadKeyboard() }
},
- Setting(context, Settings.PREF_VIBRATE_ON, R.string.vibrate_on_keypress) {
- SwitchPreference(it, Defaults.PREF_VIBRATE_ON)
+ Setting(context, Settings.PREF_VIBRATION_TYPE, R.string.vibrate_on_keypress) {
+ ListPreference(
+ it,
+ listOf(
+ stringResource(R.string.prefs_keypress_vibration_mode_off) to AudioAndHapticFeedbackManager.VibrationType.OFF.toString(),
+ stringResource(R.string.prefs_keypress_vibration_mode_system) to AudioAndHapticFeedbackManager.VibrationType.SYSTEM.toString(),
+ stringResource(R.string.prefs_keypress_vibration_mode_custom) to AudioAndHapticFeedbackManager.VibrationType.CUSTOM.toString(),
+ ),
+ Defaults.PREF_VIBRATION_TYPE
+ )
},
Setting(context, Settings.PREF_VIBRATE_IN_DND_MODE, R.string.vibrate_in_dnd_mode) {
SwitchPreference(it, Defaults.PREF_VIBRATE_IN_DND_MODE)
@@ -192,8 +205,34 @@ fun createPreferencesSettings(context: Context) = listOf(
if (it < 0) stringResource(R.string.settings_system_default)
else stringResource(R.string.abbreviation_unit_milliseconds, it.toString())
},
- range = -1f..100f,
- onValueChanged = { it?.let { AudioAndHapticFeedbackManager.getInstance().vibrate(it.toLong()) } }
+ range = 0f..100f,
+ onValueChanged = {
+ it?.let {
+ AudioAndHapticFeedbackManager.getInstance().vibrate(
+ it.toLong(),
+ Settings.getInstance().current.mKeypressVibrationAmplitude
+ )
+ }
+ }
+ )
+ },
+ Setting(context, Settings.PREF_VIBRATION_AMPLITUDE_SETTINGS, R.string.prefs_keypress_vibration_amplitude_settings) { setting ->
+ SliderPreference(
+ name = setting.title,
+ key = setting.key,
+ default = Defaults.PREF_VIBRATION_AMPLITUDE_SETTINGS,
+ description = {
+ if (it == 255) stringResource(R.string.settings_system_default)
+ else it.toString()
+ },
+ range = 0f..255f,
+ onValueChanged = {
+ it?.let {
+ AudioAndHapticFeedbackManager.getInstance().vibrate(
+ Settings.getInstance().current.mKeypressVibrationDuration.toLong(), it.toInt()
+ )
+ }
+ }
)
},
Setting(context, Settings.PREF_KEYPRESS_SOUND_VOLUME, R.string.prefs_keypress_sound_volume_settings) { setting ->
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6918a79aa3..02e036f6fb 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -546,8 +546,13 @@ language, hence "No language". -->
Day
Night
+ Off
+ System default
+ Custom
Keypress vibration duration
+
+ Keypress vibration intensity
Keypress sound volume