diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d3bd9b86bf..17343701cf 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -657,6 +657,7 @@
Missed BG readings
raise_urgent_alarms_as_android_notification
Use system notifications for alerts and notifications
+ Gradually increase the volume for alerts and notifications
enable_pump_unreachable_alert
enable_missed_bg_readings
enable_carbs_required_alert_local
diff --git a/app/src/main/res/xml/pref_alerts.xml b/app/src/main/res/xml/pref_alerts.xml
index a7783f7954..ebb71e5611 100644
--- a/app/src/main/res/xml/pref_alerts.xml
+++ b/app/src/main/res/xml/pref_alerts.xml
@@ -47,6 +47,11 @@
android:key="@string/key_raise_notifications_as_android_notifications"
android:title="@string/raise_notifications_as_android_notifications" />
+
+
diff --git a/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundService.kt b/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundService.kt
index f84e6af6e2..8f5eb74190 100644
--- a/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundService.kt
+++ b/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundService.kt
@@ -4,6 +4,7 @@ import android.content.Context
import android.content.Intent
import android.media.AudioManager
import android.media.MediaPlayer
+import android.os.Handler
import android.os.IBinder
import dagger.android.DaggerService
import info.nightscout.androidaps.core.R
@@ -11,16 +12,38 @@ import info.nightscout.androidaps.interfaces.NotificationHolderInterface
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.utils.resources.ResourceHelper
+import info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject
+import kotlin.math.ln
+import kotlin.math.pow
class AlarmSoundService : DaggerService() {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var notificationHolder: NotificationHolderInterface
+ @Inject lateinit var sp: SP
private var player: MediaPlayer? = null
private var resourceId = R.raw.error
+ companion object {
+ private const val VOLUME_INCREASE_STEPS = 40; // Total number of steps to increase volume with
+ private const val VOLUME_INCREASE_INITIAL_SILENT_TIME_MILLIS = 3_000L; // Number of milliseconds that the notification should initially be silent
+ private const val VOLUME_INCREASE_BASE_DELAY_MILLIS = 15_000; // Base delay between volume increments
+ private const val VOLUME_INCREASE_MIN_DELAY_MILLIS = 2_000L; // Minimum delay between volume increments
+
+ /*
+ * Delay until the next volumen increment will be the lowest value of VOLUME_INCREASE_MIN_DELAY_MILLIS and
+ * VOLUME_INCREASE_BASE_DELAY_MILLIS - (currentVolumeLevel - 1) ^ VOLUME_INCREASE_DELAY_DECREMENT_EXPONENT * 1000
+ *
+ */
+ private const val VOLUME_INCREASE_DELAY_DECREMENT_EXPONENT = 2.0;
+
+ }
+
+ private val handler = Handler()
+ private var currentVolumeLevel = 0
+
override fun onBind(intent: Intent): IBinder? = null
override fun onCreate() {
@@ -41,10 +64,16 @@ class AlarmSoundService : DaggerService() {
val afd = resourceHelper.openRawResourceFd(resourceId) ?: return START_STICKY
player?.setDataSource(afd.fileDescriptor, afd.startOffset, afd.length)
afd.close()
- player?.isLooping = true // Set looping
- val manager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
- if (!manager.isMusicActive) {
- player?.setVolume(100f, 100f)
+ player?.isLooping = true
+ val audioManager = getAudioManager();
+ if (!audioManager.isMusicActive) {
+ if (sp.getBoolean(R.string.key_gradually_increase_notification_volume, false)) {
+ currentVolumeLevel = 0;
+ player?.setVolume(0f, 0f)
+ handler.postDelayed(volumeUpdater, VOLUME_INCREASE_INITIAL_SILENT_TIME_MILLIS)
+ } else {
+ player?.setVolume(1f, 1f)
+ }
}
player?.prepare()
player?.start()
@@ -55,8 +84,38 @@ class AlarmSoundService : DaggerService() {
}
override fun onDestroy() {
+ handler.removeCallbacks(volumeUpdater)
player?.stop()
player?.release()
aapsLogger.debug(LTag.CORE, "onDestroy")
}
+
+ private fun getAudioManager(): AudioManager {
+ return getSystemService(Context.AUDIO_SERVICE) as AudioManager
+ }
+
+ // TODO replace with VolumeShaper when min API level >= 26
+ private val volumeUpdater = object : Runnable {
+ override fun run() {
+ if (player?.isPlaying == true) {
+ currentVolumeLevel++;
+
+ val volumePercentage = 100.0.coerceAtMost(currentVolumeLevel / VOLUME_INCREASE_STEPS.toDouble() * 100)
+ val volume = 1 - (ln(1.0.coerceAtLeast(100.0 - volumePercentage)) / ln(100.0))
+
+ aapsLogger.debug(LTag.CORE, "Setting notification volume to {} ({} %)", volume, volumePercentage)
+
+ val floatVolume = volume.toFloat()
+ player?.setVolume(floatVolume, floatVolume)
+
+ if (currentVolumeLevel < VOLUME_INCREASE_STEPS) {
+ // Increase volume faster as time goes by
+ val delay = VOLUME_INCREASE_MIN_DELAY_MILLIS.coerceAtLeast(VOLUME_INCREASE_BASE_DELAY_MILLIS -
+ ((currentVolumeLevel - 1).toDouble().pow(VOLUME_INCREASE_DELAY_DECREMENT_EXPONENT) * 1000).toLong())
+ aapsLogger.debug(LTag.CORE, "Next notification volume increment in {}ms", delay)
+ handler.postDelayed(this, delay);
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 9ed19651f5..7d8c9b865b 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -22,6 +22,7 @@
ns_uploadlocalprofile
bt_watchdog
bt_watchdog_last
+ gradually_increase_notification_volume
Pairing
@@ -281,5 +282,4 @@
-
\ No newline at end of file