Understand the domain layer with Alarm interface, AlarmCore state machine, Alarms manager, and event system
The domain layer contains the core business logic for alarm management. It’s independent of Android framework details and defines clear interfaces for the UI layer.
The Alarm interface defines operations available on individual alarms:
Alarm.kt
interface Alarm { fun enable(enable: Boolean) fun snooze() fun snooze(hourOfDay: Int, minute: Int) fun dismiss() fun requestSkip() fun isSkipping(): Boolean fun delete() // Change something and commit fun edit(func: AlarmValue.() -> AlarmValue) val id: Int val labelOrDefault: String val alarmtone: Alarmtone val data: AlarmValue}
The edit() function uses a functional approach, taking a lambda that transforms the current AlarmValue and immediately persists the change.
The AlarmCore class implements the Alarm interface and manages alarm lifecycle using a state machine. Each alarm instance maintains its own state and handles transitions based on events.
The Alarms class implements IAlarmsManager and manages all alarm instances:
Alarms.kt
class Alarms( private val prefs: Prefs, private val store: Store, private val calendars: Calendars, private val alarmsScheduler: IAlarmsScheduler, private val broadcaster: AlarmCore.IStateNotifier, private val alarmsRepository: AlarmsRepository, private val logger: Logger, private val databaseQuery: DatabaseQuery,) : IAlarmsManager, DatastoreMigration { private val alarms: MutableMap<Int, AlarmCore> = mutableMapOf() fun start() { alarms.putAll( alarmsRepository.query().associate { store -> store.id to createAlarm(store) } ) alarms.values.forEach { it.start() } if (!alarmsRepository.initialized) { migrateDatabase() if (alarms.isEmpty()) { insertDefaultAlarms() } } } override fun createNewAlarm(): Alarm { val alarm = createAlarm(alarmsRepository.create()) alarms[alarm.id] = alarm alarm.start() return alarm } override fun getAlarm(alarmId: Int): AlarmCore? { return alarms[alarmId] } private fun createAlarm(alarmStore: AlarmStore): AlarmCore { return AlarmCore( alarmStore, logger, alarmsScheduler, broadcaster, prefs, store, calendars, onDelete = { alarms.remove(it) }, ) }}
The Alarms class acts as a factory and registry for AlarmCore instances. It handles initialization, migration from SQLite, and creation of default alarms on first launch.
The domain layer delegates actual alarm scheduling to IAlarmsScheduler:
interface IAlarmsScheduler { fun setAlarm(id: Int, type: CalendarType, calendar: Calendar, alarmValue: AlarmValue) fun removeAlarm(id: Int) fun setInexactAlarm(id: Int, calendar: Calendar) fun removeInexactAlarm(id: Int)}
This abstraction allows the domain layer to remain independent of Android’s AlarmManager APIs.