Per wekker eigen geluid instelbaar via systeem-ringtone-kiezer; standaard blijft de systeem-alarmtoon
This commit is contained in:
parent
35db28c7f1
commit
b537724b75
5 changed files with 139 additions and 11 deletions
|
|
@ -11,6 +11,7 @@ import android.widget.TextView
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import nl.eddydevink.buschauffeurswekker.core.AlarmScheduler
|
||||
import nl.eddydevink.buschauffeurswekker.core.Notifier
|
||||
import nl.eddydevink.buschauffeurswekker.core.Prefs
|
||||
import nl.eddydevink.buschauffeurswekker.core.Ringer
|
||||
import nl.eddydevink.buschauffeurswekker.receivers.AlarmRingReceiver
|
||||
import java.time.Instant
|
||||
|
|
@ -22,6 +23,7 @@ import java.time.format.DateTimeFormatter
|
|||
class AlarmActivity : AppCompatActivity() {
|
||||
|
||||
private var ringer: Ringer? = null
|
||||
private var alarmName: String = ""
|
||||
|
||||
private val clockTick = object : Runnable {
|
||||
override fun run() {
|
||||
|
|
@ -61,6 +63,7 @@ class AlarmActivity : AppCompatActivity() {
|
|||
|
||||
private fun bindUi() {
|
||||
val name = intent?.getStringExtra(AlarmScheduler.EXTRA_NAME) ?: "Wekker"
|
||||
alarmName = name
|
||||
val ringTime = intent?.getLongExtra(AlarmScheduler.EXTRA_RING_TIME, System.currentTimeMillis())
|
||||
?: System.currentTimeMillis()
|
||||
val snoozed = intent?.getBooleanExtra(AlarmScheduler.EXTRA_SNOOZED, false) ?: false
|
||||
|
|
@ -79,7 +82,8 @@ class AlarmActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
private fun startRinging() {
|
||||
ringer = Ringer(this).also { it.start() }
|
||||
val uri = Prefs(this).ringtoneFor(alarmName)
|
||||
ringer = Ringer(this, uri).also { it.start() }
|
||||
handler.removeCallbacks(clockTick)
|
||||
handler.post(clockTick)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,41 @@
|
|||
package nl.eddydevink.buschauffeurswekker
|
||||
|
||||
import android.content.Intent
|
||||
import android.media.RingtoneManager
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.widget.EditText
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import nl.eddydevink.buschauffeurswekker.core.Prefs
|
||||
|
||||
/** Apart instellingenscherm: CalDAV-gegevens (URL, gebruiker, app-wachtwoord). */
|
||||
/**
|
||||
* Instellingen: CalDAV-gegevens en per wekker een eigen geluid
|
||||
* (via de systeem-ringtone-kiezer; "Standaard geluid" = systeem-alarmtoon).
|
||||
*/
|
||||
class SettingsActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var prefs: Prefs
|
||||
private var pendingSoundName: String? = null
|
||||
|
||||
private val ringtonePicker =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
val name = pendingSoundName ?: return@registerForActivityResult
|
||||
pendingSoundName = null
|
||||
if (result.resultCode == RESULT_OK) {
|
||||
val uri = result.data?.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI) as Uri?
|
||||
prefs.setRingtone(name, uri)
|
||||
updateSoundRow(name)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_settings)
|
||||
|
||||
val prefs = Prefs(this)
|
||||
prefs = Prefs(this)
|
||||
findViewById<EditText>(R.id.et_url).setText(prefs.calendarUrl.orEmpty())
|
||||
findViewById<EditText>(R.id.et_user).setText(prefs.username.orEmpty())
|
||||
findViewById<EditText>(R.id.et_pass).setText(prefs.password.orEmpty())
|
||||
|
|
@ -26,5 +47,52 @@ class SettingsActivity : AppCompatActivity() {
|
|||
Toast.makeText(this, "Instellingen opgeslagen", Toast.LENGTH_SHORT).show()
|
||||
finish()
|
||||
}
|
||||
|
||||
findViewById<MaterialButton>(R.id.btn_sound_opstaan).setOnClickListener { openSoundPicker("Opstaan") }
|
||||
findViewById<MaterialButton>(R.id.btn_sound_wally).setOnClickListener { openSoundPicker("Wally") }
|
||||
findViewById<MaterialButton>(R.id.btn_sound_vertrek).setOnClickListener { openSoundPicker("Vertrek") }
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
SOUND_ALARMS.forEach { updateSoundRow(it) }
|
||||
}
|
||||
|
||||
private fun openSoundPicker(name: String) {
|
||||
pendingSoundName = name
|
||||
val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply {
|
||||
putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_ALARM)
|
||||
putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, "Geluid voor $name")
|
||||
putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true)
|
||||
putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false)
|
||||
putExtra(
|
||||
RingtoneManager.EXTRA_RINGTONE_EXISTING_URI,
|
||||
prefs.ringtoneFor(name)
|
||||
?: RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM),
|
||||
)
|
||||
}
|
||||
ringtonePicker.launch(intent)
|
||||
}
|
||||
|
||||
private fun updateSoundRow(name: String) {
|
||||
val uri = prefs.ringtoneFor(name)
|
||||
val label = if (uri != null) {
|
||||
RingtoneManager.getRingtone(this, uri)?.getTitle(this) ?: "Eigen geluid"
|
||||
} else {
|
||||
"Standaard"
|
||||
}
|
||||
findViewById<MaterialButton>(SOUND_BUTTON_ID[name]!!).text = "$name — $label"
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val ALARM_OPSTAAN = "Opstaan"
|
||||
const val ALARM_WALLY = "Wally"
|
||||
const val ALARM_VERTREK = "Vertrek"
|
||||
val SOUND_ALARMS = listOf(ALARM_OPSTAAN, ALARM_WALLY, ALARM_VERTREK)
|
||||
val SOUND_BUTTON_ID = mapOf(
|
||||
ALARM_OPSTAAN to R.id.btn_sound_opstaan,
|
||||
ALARM_WALLY to R.id.btn_sound_wally,
|
||||
ALARM_VERTREK to R.id.btn_sound_vertrek,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package nl.eddydevink.buschauffeurswekker.core
|
|||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import androidx.security.crypto.EncryptedSharedPreferences
|
||||
import androidx.security.crypto.MasterKey
|
||||
import java.time.Instant
|
||||
|
|
@ -83,6 +84,16 @@ class Prefs(context: Context) {
|
|||
} else null
|
||||
}
|
||||
|
||||
/** Gekozen geluid voor een wekker (naam), of null voor het systeemgeluid. */
|
||||
fun ringtoneFor(name: String): Uri? =
|
||||
sp.getString("ringtone_$name", null)?.let {
|
||||
runCatching { Uri.parse(it) }.getOrNull()
|
||||
}
|
||||
|
||||
fun setRingtone(name: String, uri: Uri?) {
|
||||
sp.edit().putString("ringtone_$name", uri?.toString()).apply()
|
||||
}
|
||||
|
||||
fun storePlan(day: LocalDate, alarms: List<AlarmSpec>) {
|
||||
val zone = ZoneId.systemDefault()
|
||||
plannedDayIso = day.toString()
|
||||
|
|
|
|||
|
|
@ -10,22 +10,35 @@ import android.os.VibrationEffect
|
|||
import android.os.Vibrator
|
||||
import android.os.VibratorManager
|
||||
|
||||
/** Speelt het standaard wekkergeluid (herhalend) en laat de telefoon trillen. */
|
||||
class Ringer(private val context: Context) {
|
||||
/**
|
||||
* Speelt het wekkergeluid (herhalend) en laat de telefoon trillen.
|
||||
* Een eigen gekozen geluid ([chosenUri], null = systeem-alarmtoon) wordt
|
||||
* afgespeeld; valt die weg (verwijderd bestand), dan valt het terug op de
|
||||
* standaard alarmtoon en daarna de beltoon.
|
||||
*/
|
||||
class Ringer(
|
||||
private val context: Context,
|
||||
private val chosenUri: Uri? = null,
|
||||
) {
|
||||
|
||||
private var player: MediaPlayer? = null
|
||||
private var vibrator: Vibrator? = null
|
||||
|
||||
fun start() {
|
||||
val uri = RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_ALARM)
|
||||
?: RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE)
|
||||
playLooping(uri)
|
||||
val candidates = listOfNotNull(
|
||||
chosenUri,
|
||||
RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_ALARM),
|
||||
RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE),
|
||||
)
|
||||
for (uri in candidates) {
|
||||
if (playLooping(uri)) break
|
||||
}
|
||||
vibrate()
|
||||
}
|
||||
|
||||
private fun playLooping(uri: Uri?) {
|
||||
if (uri == null) return
|
||||
try {
|
||||
/** @return true als het geluid is gestart. */
|
||||
private fun playLooping(uri: Uri): Boolean {
|
||||
return try {
|
||||
player = MediaPlayer().apply {
|
||||
setAudioAttributes(
|
||||
AudioAttributes.Builder()
|
||||
|
|
@ -38,8 +51,10 @@ class Ringer(private val context: Context) {
|
|||
prepare()
|
||||
start()
|
||||
}
|
||||
true
|
||||
} catch (t: Throwable) {
|
||||
player = null
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,5 +46,35 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Opslaan" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="Wekkergeluiden"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_sound_opstaan"
|
||||
style="@style/Widget.Material3.Button.TonalButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="Opstaan — Standaard" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_sound_wally"
|
||||
style="@style/Widget.Material3.Button.TonalButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Wally — Standaard" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_sound_vertrek"
|
||||
style="@style/Widget.Material3.Button.TonalButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Vertrek — Standaard" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
Loading…
Reference in a new issue