Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions app/src/main/java/helium314/keyboard/latin/AppUpgrade.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -38,6 +41,12 @@ public static AudioAndHapticFeedbackManager getInstance() {
return sInstance;
}

public enum VibrationType {
OFF,
SYSTEM,
CUSTOM;
}

private AudioAndHapticFeedbackManager() {
// Intentional empty constructor for singleton.
}
Expand All @@ -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() {
Expand Down Expand Up @@ -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);
}
}

Expand Down
11 changes: 6 additions & 5 deletions app/src/main/java/helium314/keyboard/latin/LatinIME.java
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is code here commented out?

// 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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 = ");
Expand Down Expand Up @@ -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 = ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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))
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 ->
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -546,8 +546,13 @@ language, hence "No language". -->
<string name="day_or_night_day">Day</string>
<!-- Button for selecting night -->
<string name="day_or_night_night">Night</string>
<string name="prefs_keypress_vibration_mode_off">Off</string>
<string name="prefs_keypress_vibration_mode_system">System default</string>
<string name="prefs_keypress_vibration_mode_custom">Custom</string>
Comment on lines +549 to +551
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing comments here, right?

<!-- Title of the setting for keypress vibration duration -->
<string name="prefs_keypress_vibration_duration_settings">Keypress vibration duration</string>
<!-- Title of the setting for keypress vibration amplitude -->
<string name="prefs_keypress_vibration_amplitude_settings">Keypress vibration intensity</string>
<!-- Title of the setting for keypress sound volume -->
<string name="prefs_keypress_sound_volume_settings">Keypress sound volume</string>
<!-- Title of the setting for key long press delay -->
Expand Down