diff --git a/README.md b/README.md index c19bbdc..8a92f25 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,9 @@ Choose between: Playback runs for the configured number of seconds (`5–300`, default **30**), then the previous volume is restored. +### Volume +The ring plays at a configurable percentage (`1–100%`) of the alarm-stream volume. + --- ## How Do Not Disturb Override Works (read this) @@ -50,7 +53,7 @@ Only after the user flips that toggle will a trigger actually ring. When access **is** granted, `RingService`: - saves the current **alarm-stream** volume, -- forces `AudioManager.STREAM_ALARM` to max, +- sets `AudioManager.STREAM_ALARM` to the configured volume percentage, - requests `AUDIOFOCUS_GAIN_TRANSIENT` using `AudioAttributes.USAGE_ALARM`, - plays on the **alarm stream** — the one stream Do Not Disturb does **not** silence by default (media/music *is* silenced), which is what lets the ring diff --git a/app/src/main/java/com/example/lostmyphone/RingConfig.kt b/app/src/main/java/com/example/lostmyphone/RingConfig.kt index 7e9aad3..379a5fe 100644 --- a/app/src/main/java/com/example/lostmyphone/RingConfig.kt +++ b/app/src/main/java/com/example/lostmyphone/RingConfig.kt @@ -23,6 +23,7 @@ object RingConfig { private const val KEY_RINGTONE_URI = "ringtone_uri" private const val KEY_SONG_URI = "song_uri" private const val KEY_DURATION_SEC = "duration_sec" + private const val KEY_VOLUME_PERCENT = "volume_percent" const val SOUND_RINGTONE = "ringtone" const val SOUND_SONG = "song" @@ -82,6 +83,12 @@ object RingConfig { fun setDurationSeconds(context: Context, seconds: Int): Boolean = prefs(context).edit().putInt(KEY_DURATION_SEC, seconds.coerceIn(MIN_DURATION_SEC, MAX_DURATION_SEC)).commit() + fun volumePercent(context: Context): Int = + prefs(context).getInt(KEY_VOLUME_PERCENT, 100).coerceIn(1, 100) + + fun setVolumePercent(context: Context, percent: Int): Boolean = + prefs(context).edit().putInt(KEY_VOLUME_PERCENT, percent.coerceIn(1, 100)).commit() + /** * The Uri the RingService should actually play. * - ringtone mode -> the system default ringtone, diff --git a/app/src/main/java/com/example/lostmyphone/RingService.kt b/app/src/main/java/com/example/lostmyphone/RingService.kt index d2fc68b..1bec219 100644 --- a/app/src/main/java/com/example/lostmyphone/RingService.kt +++ b/app/src/main/java/com/example/lostmyphone/RingService.kt @@ -158,11 +158,12 @@ class RingService : Service() { // Step 1: save current alarm-stream volume so we can restore it later. originalVolume = audioManager.getStreamVolume(AudioManager.STREAM_ALARM) - // Step 2: force the alarm stream to max volume. + // Step 2: force the alarm stream to the configured volume percentage. val maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_ALARM) + val targetVolume = (maxVolume * RingConfig.volumePercent(this) / 100).coerceAtLeast(1) audioManager.setStreamVolume( AudioManager.STREAM_ALARM, - maxVolume, + targetVolume, 0 // flags = 0 so we do NOT show the system volume UI. ) diff --git a/app/src/main/java/com/example/lostmyphone/SettingsActivity.kt b/app/src/main/java/com/example/lostmyphone/SettingsActivity.kt index 9412087..588679a 100644 --- a/app/src/main/java/com/example/lostmyphone/SettingsActivity.kt +++ b/app/src/main/java/com/example/lostmyphone/SettingsActivity.kt @@ -36,6 +36,8 @@ class SettingsActivity : AppCompatActivity() { private lateinit var tvSelectedSound: TextView private lateinit var sbDuration: SeekBar private lateinit var tvDurationValue: TextView + private lateinit var sbVolume: SeekBar + private lateinit var tvVolumeValue: TextView private lateinit var btnSave: Button private var pickedRingtoneUri: Uri? = null @@ -88,10 +90,13 @@ class SettingsActivity : AppCompatActivity() { tvSelectedSound = findViewById(R.id.tvSelectedSound) sbDuration = findViewById(R.id.sbDuration) tvDurationValue = findViewById(R.id.tvDurationValue) + sbVolume = findViewById(R.id.sbVolume) + tvVolumeValue = findViewById(R.id.tvVolumeValue) btnSave = findViewById(R.id.btnSave) loadCurrentValues() setupDurationSeekBar() + setupVolumeSeekBar() setupPickers() btnSave.setOnClickListener { saveSettings() } @@ -108,6 +113,9 @@ class SettingsActivity : AppCompatActivity() { sbDuration.progress = RingConfig.durationSeconds(this) - RingConfig.MIN_DURATION_SEC updateDurationLabel() + + sbVolume.progress = RingConfig.volumePercent(this) - 1 + updateVolumeLabel() updateSoundSummary() } @@ -129,6 +137,22 @@ class SettingsActivity : AppCompatActivity() { tvDurationValue.text = getString(R.string.duration_value, seconds) } + private fun setupVolumeSeekBar() { + sbVolume.max = 99 // 1..100 + sbVolume.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { + updateVolumeLabel() + } + + override fun onStartTrackingTouch(seekBar: SeekBar) {} + override fun onStopTrackingTouch(seekBar: SeekBar) {} + }) + } + + private fun updateVolumeLabel() { + tvVolumeValue.text = getString(R.string.volume_value, sbVolume.progress + 1) + } + private fun setupPickers() { btnPickRingtone.setOnClickListener { val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply { @@ -186,12 +210,14 @@ class SettingsActivity : AppCompatActivity() { val mode = if (rdbSong.isChecked) RingConfig.SOUND_SONG else RingConfig.SOUND_RINGTONE val seconds = sbDuration.progress + RingConfig.MIN_DURATION_SEC + val volume = sbVolume.progress + 1 RingConfig.setTriggerText(this, trigger) RingConfig.setSoundMode(this, mode) RingConfig.setRingtoneUri(this, pickedRingtoneUri) RingConfig.setSongUri(this, pickedSongUri) RingConfig.setDurationSeconds(this, seconds) + RingConfig.setVolumePercent(this, volume) Toast.makeText(this, R.string.toast_saved, Toast.LENGTH_SHORT).show() finish() diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 30bd3b1..4eb1b52 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -138,6 +138,33 @@ android:text="@string/label_duration_range" android:textSize="12sp" /> + + + + + + + + +