Add support for setting the notification vibration pattern on Android 8+

This commit is contained in:
cketti 2021-12-22 02:59:27 +01:00
parent 53112bc5fb
commit 955b22b970
4 changed files with 71 additions and 19 deletions

View file

@ -147,13 +147,15 @@ class NotificationChannelManager(
}
@RequiresApi(Build.VERSION_CODES.O)
fun getNotificationLightConfiguration(account: Account): NotificationLightConfiguration {
fun getNotificationConfiguration(account: Account): NotificationConfiguration {
val channelId = getChannelIdFor(account, ChannelType.MESSAGES)
val notificationChannel = notificationManager.getNotificationChannel(channelId)
return NotificationLightConfiguration(
isEnabled = notificationChannel.shouldShowLights(),
color = notificationChannel.lightColor
return NotificationConfiguration(
isBlinkLightsEnabled = notificationChannel.shouldShowLights(),
lightColor = notificationChannel.lightColor,
isVibrationEnabled = notificationChannel.shouldVibrate(),
vibrationPattern = notificationChannel.vibrationPattern?.toList()
)
}
@ -190,14 +192,14 @@ class NotificationChannelManager(
@RequiresApi(Build.VERSION_CODES.O)
private fun NotificationChannel.matches(notificationSetting: NotificationSetting): Boolean {
return lightColor == notificationSetting.ledColor
return lightColor == notificationSetting.ledColor &&
vibrationPattern.contentEquals(notificationSetting.vibration)
}
@RequiresApi(Build.VERSION_CODES.O)
private fun NotificationChannel.copyPropertiesFrom(otherNotificationChannel: NotificationChannel) {
setShowBadge(otherNotificationChannel.canShowBadge())
setSound(otherNotificationChannel.sound, otherNotificationChannel.audioAttributes)
vibrationPattern = otherNotificationChannel.vibrationPattern
enableVibration(otherNotificationChannel.shouldVibrate())
enableLights(otherNotificationChannel.shouldShowLights())
setBypassDnd(otherNotificationChannel.canBypassDnd())
@ -210,13 +212,18 @@ class NotificationChannelManager(
@RequiresApi(Build.VERSION_CODES.O)
private fun NotificationChannel.copyPropertiesFrom(notificationSetting: NotificationSetting) {
lightColor = notificationSetting.ledColor
if (shouldVibrate()) {
vibrationPattern = notificationSetting.vibration
}
}
private val Account.messagesNotificationChannelSuffix: String
get() = messagesNotificationChannelVersion.let { version -> if (version == 0) "" else "_$version" }
}
data class NotificationLightConfiguration(
val isEnabled: Boolean,
val color: Int
data class NotificationConfiguration(
val isBlinkLightsEnabled: Boolean,
val lightColor: Int,
val isVibrationEnabled: Boolean,
val vibrationPattern: List<Long>?
)

View file

@ -258,5 +258,6 @@ class AccountSettingsDataStore(
val (vibrationPattern, vibrationTimes) = VibrationPatternPreference.decode(value)
account.notificationSetting.vibratePattern = vibrationPattern
account.notificationSetting.vibrateTimes = vibrationTimes
notificationSettingsChanged = true
}
}

View file

@ -51,6 +51,7 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), ConfirmationDialogFr
private val notificationChannelManager: NotificationChannelManager by inject()
private lateinit var dataStore: AccountSettingsDataStore
private var notificationLightColorPreference: ColorPickerPreference? = null
private var notificationVibrationPatternPreference: VibrationPatternPreference? = null
private val accountUuid: String by lazy {
checkNotNull(arguments?.getString(ARG_ACCOUNT_UUID)) { "$ARG_ACCOUNT_UUID == null" }
@ -93,7 +94,7 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), ConfirmationDialogFr
val account = getAccount()
initializeCryptoSettings(account)
updateNotificationLightColorPreference(account)
maybeUpdateNotificationPreferences(account)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -193,6 +194,12 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), ConfirmationDialogFr
preference.isEnabled = false
}
findPreference<VibrationPatternPreference>(PREFERENCE_NOTIFICATION_VIBRATION_PATTERN)?.let { preference ->
notificationVibrationPatternPreference = preference
preference.dependency = null
preference.isEnabled = false
}
PRE_SDK26_NOTIFICATION_PREFERENCES.forEach { findPreference<Preference>(it).remove() }
findPreference<NotificationsPreference>(PREFERENCE_NOTIFICATION_SETTINGS_MESSAGES)?.let {
@ -211,15 +218,29 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), ConfirmationDialogFr
}
}
@SuppressLint("NewApi")
private fun updateNotificationLightColorPreference(account: Account) {
notificationLightColorPreference?.let { preference ->
val notificationLightConfiguration = notificationChannelManager.getNotificationLightConfiguration(account)
val blinkLightsEnabled = notificationLightConfiguration.isEnabled
private fun maybeUpdateNotificationPreferences(account: Account) {
if (notificationLightColorPreference != null || notificationVibrationPatternPreference != null) {
updateNotificationPreferences(account)
}
}
@SuppressLint("NewApi")
private fun updateNotificationPreferences(account: Account) {
val notificationConfiguration = notificationChannelManager.getNotificationConfiguration(account)
notificationLightColorPreference?.let { preference ->
val blinkLightsEnabled = notificationConfiguration.isBlinkLightsEnabled
preference.isEnabled = blinkLightsEnabled
if (blinkLightsEnabled) {
preference.color = notificationLightConfiguration.color
preference.color = notificationConfiguration.lightColor
}
}
notificationVibrationPatternPreference?.let { preference ->
val vibrationEnabled = notificationConfiguration.isVibrationEnabled
preference.isEnabled = vibrationEnabled
if (vibrationEnabled) {
preference.setVibrationPatternFromSystem(notificationConfiguration.vibrationPattern)
}
}
}
@ -412,6 +433,7 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), ConfirmationDialogFr
private const val PREFERENCE_SPAM_FOLDER = "spam_folder"
private const val PREFERENCE_TRASH_FOLDER = "trash_folder"
private const val PREFERENCE_NOTIFICATION_LIGHT_COLOR = "led_color"
private const val PREFERENCE_NOTIFICATION_VIBRATION_PATTERN = "account_combined_vibration_pattern"
private const val PREFERENCE_NOTIFICATION_CHANNELS = "notification_channels"
private const val PREFERENCE_NOTIFICATION_SETTINGS_MESSAGES = "open_notification_settings_messages"
private const val PREFERENCE_NOTIFICATION_SETTINGS_MISCELLANEOUS = "open_notification_settings_miscellaneous"
@ -420,7 +442,6 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), ConfirmationDialogFr
private val PRE_SDK26_NOTIFICATION_PREFERENCES = arrayOf(
"account_ringtone",
"account_vibrate",
"account_combined_vibration_pattern",
"account_led",
)

View file

@ -5,6 +5,7 @@ import android.content.Context
import android.util.AttributeSet
import androidx.core.content.res.TypedArrayUtils
import androidx.preference.ListPreference
import com.fsck.k9.NotificationSetting
import com.takisoft.preferencex.PreferenceFragmentCompat
/**
@ -23,10 +24,10 @@ constructor(
),
defStyleRes: Int = 0
) : ListPreference(context, attrs, defStyleAttr, defStyleRes) {
internal var vibrationPattern: Int = 0
internal var vibrationPattern: Int = DEFAULT_VIBRATION_PATTERN
private set
internal var vibrationTimes: Int = 1
internal var vibrationTimes: Int = DEFAULT_VIBRATION_TIMES
private set
override fun onSetInitialValue(defaultValue: Any?) {
@ -53,12 +54,34 @@ constructor(
updateSummary()
}
fun setVibrationPatternFromSystem(combinedPattern: List<Long>?) {
if (combinedPattern == null || combinedPattern.size < 2 || combinedPattern.size % 2 != 0) {
setVibrationPattern(DEFAULT_VIBRATION_PATTERN, DEFAULT_VIBRATION_TIMES)
return
}
val combinedPatternArray = combinedPattern.toLongArray()
val vibrationTimes = combinedPattern.size / 2
val vibrationPattern = entryValues.asSequence()
.map { entryValue -> entryValue.toString().toInt() }
.firstOrNull { vibrationPattern ->
val testPattern = NotificationSetting.getVibration(vibrationPattern, vibrationTimes)
testPattern.contentEquals(combinedPatternArray)
} ?: DEFAULT_VIBRATION_PATTERN
setVibrationPattern(vibrationPattern, vibrationTimes)
}
private fun updateSummary() {
val index = entryValues.indexOf(vibrationPattern.toString())
summary = entries[index]
}
companion object {
private const val DEFAULT_VIBRATION_PATTERN = 0
private const val DEFAULT_VIBRATION_TIMES = 1
init {
PreferenceFragmentCompat.registerPreferenceFragment(
VibrationPatternPreference::class.java, VibrationPatternDialogFragment::class.java