feat: Add support for custom notification

This commit is contained in:
Myzel394 2023-10-23 18:10:24 +02:00
parent 6ef60942e0
commit d0d8996227
No known key found for this signature in database
GPG Key ID: 79CC92F37B3E1A2B
3 changed files with 82 additions and 44 deletions

View File

@ -13,7 +13,7 @@ import java.io.InputStream
import java.io.OutputStream import java.io.OutputStream
import java.time.LocalDateTime import java.time.LocalDateTime
class AppSettingsSerializer: Serializer<AppSettings> { class AppSettingsSerializer : Serializer<AppSettings> {
override val defaultValue: AppSettings = AppSettings.getDefaultInstance() override val defaultValue: AppSettings = AppSettings.getDefaultInstance()
override suspend fun readFrom(input: InputStream): AppSettings { override suspend fun readFrom(input: InputStream): AppSettings {
@ -39,8 +39,9 @@ class AppSettingsSerializer: Serializer<AppSettings> {
} }
} }
class LocalDateTimeSerializer: KSerializer<LocalDateTime> { class LocalDateTimeSerializer : KSerializer<LocalDateTime> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("LocalDateTime", PrimitiveKind.STRING) override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor("LocalDateTime", PrimitiveKind.STRING)
override fun deserialize(decoder: Decoder): LocalDateTime { override fun deserialize(decoder: Decoder): LocalDateTime {
return LocalDateTime.parse(decoder.decodeString()) return LocalDateTime.parse(decoder.decodeString())

View File

@ -23,7 +23,7 @@ import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
abstract class RecorderService: Service() { abstract class RecorderService : Service() {
private val binder = RecorderBinder() private val binder = RecorderBinder()
private var isPaused: Boolean = false private var isPaused: Boolean = false
@ -40,6 +40,7 @@ abstract class RecorderService: Service() {
private set private set
private lateinit var recordingTimeTimer: ScheduledExecutorService private lateinit var recordingTimeTimer: ScheduledExecutorService
var onRecordingTimeChange: ((Long) -> Unit)? = null var onRecordingTimeChange: ((Long) -> Unit)? = null
var notificationDetails: NotificationDetails? = null
protected abstract fun start() protected abstract fun start()
protected abstract fun pause() protected abstract fun pause()
@ -61,7 +62,7 @@ abstract class RecorderService: Service() {
return super.onStartCommand(intent, flags, startId) return super.onStartCommand(intent, flags, startId)
} }
inner class RecorderBinder: Binder() { inner class RecorderBinder : Binder() {
fun getService(): RecorderService = this@RecorderService fun getService(): RecorderService = this@RecorderService
} }
@ -95,10 +96,12 @@ abstract class RecorderService: Service() {
start() start()
} }
} }
RecorderState.PAUSED -> { RecorderState.PAUSED -> {
pause() pause()
isPaused = true isPaused = true
} }
RecorderState.IDLE -> { RecorderState.IDLE -> {
stop() stop()
onDestroy() onDestroy()
@ -109,6 +112,7 @@ abstract class RecorderService: Service() {
RecorderState.RECORDING -> { RecorderState.RECORDING -> {
createRecordingTimeTimer() createRecordingTimeTimer()
} }
RecorderState.PAUSED, RecorderState.IDLE -> { RecorderState.PAUSED, RecorderState.IDLE -> {
recordingTimeTimer.shutdown() recordingTimeTimer.shutdown()
} }
@ -121,7 +125,7 @@ abstract class RecorderService: Service() {
RecorderState.PAUSED RecorderState.PAUSED
).contains(newState) && ).contains(newState) &&
PermissionHelper.hasGranted(this, android.Manifest.permission.POST_NOTIFICATIONS) PermissionHelper.hasGranted(this, android.Manifest.permission.POST_NOTIFICATIONS)
){ ) {
val notification = buildNotification() val notification = buildNotification()
NotificationManagerCompat.from(this).notify( NotificationManagerCompat.from(this).notify(
NotificationHelper.RECORDER_CHANNEL_NOTIFICATION_ID, NotificationHelper.RECORDER_CHANNEL_NOTIFICATION_ID,
@ -148,19 +152,24 @@ abstract class RecorderService: Service() {
changeState(RecorderState.IDLE) changeState(RecorderState.IDLE)
stopForeground(STOP_FOREGROUND_REMOVE) stopForeground(STOP_FOREGROUND_REMOVE)
NotificationManagerCompat.from(this).cancel(NotificationHelper.RECORDER_CHANNEL_NOTIFICATION_ID) NotificationManagerCompat.from(this)
.cancel(NotificationHelper.RECORDER_CHANNEL_NOTIFICATION_ID)
stopSelf() stopSelf()
} }
private fun buildStartNotification(): Notification = NotificationCompat.Builder(this, NotificationHelper.RECORDER_CHANNEL_ID) private fun buildStartNotification(): Notification =
.setContentTitle(getString(R.string.ui_audioRecorder_state_recording_title)) NotificationCompat.Builder(this, NotificationHelper.RECORDER_CHANNEL_ID)
.setContentText(getString(R.string.ui_audioRecorder_state_recording_description)) .setContentTitle(getString(R.string.ui_audioRecorder_state_recording_title))
.setSmallIcon(R.drawable.launcher_foreground) .setContentText(getString(R.string.ui_audioRecorder_state_recording_description))
.setPriority(NotificationCompat.PRIORITY_LOW) .setSmallIcon(R.drawable.launcher_foreground)
.setCategory(NotificationCompat.CATEGORY_SERVICE) .setPriority(NotificationCompat.PRIORITY_LOW)
.build() .setCategory(NotificationCompat.CATEGORY_SERVICE)
.build()
private fun getNotificationChangeStateIntent(newState: RecorderState, requestCode: Int): PendingIntent { private fun getNotificationChangeStateIntent(
newState: RecorderState,
requestCode: Int
): PendingIntent {
return PendingIntent.getService( return PendingIntent.getService(
this, this,
requestCode, requestCode,
@ -172,14 +181,13 @@ abstract class RecorderService: Service() {
) )
} }
private fun buildNotification(): Notification = when(state) { private fun buildNotification(): Notification = when (state) {
RecorderState.RECORDING -> NotificationCompat.Builder(this, NotificationHelper.RECORDER_CHANNEL_ID) RecorderState.RECORDING -> NotificationCompat.Builder(
.setContentTitle(getString(R.string.ui_audioRecorder_state_recording_title)) this,
.setContentText(getString(R.string.ui_audioRecorder_state_recording_description)) NotificationHelper.RECORDER_CHANNEL_ID
.setSmallIcon(R.drawable.launcher_foreground) )
.setPriority(NotificationCompat.PRIORITY_LOW) .setPriority(NotificationCompat.PRIORITY_LOW)
.setCategory(NotificationCompat.CATEGORY_SERVICE) .setCategory(NotificationCompat.CATEGORY_SERVICE)
.setOngoing(true)
.setWhen( .setWhen(
Date.from( Date.from(
Calendar Calendar
@ -210,8 +218,24 @@ abstract class RecorderService: Service() {
getString(R.string.ui_audioRecorder_action_pause_label), getString(R.string.ui_audioRecorder_action_pause_label),
getNotificationChangeStateIntent(RecorderState.PAUSED, 2), getNotificationChangeStateIntent(RecorderState.PAUSED, 2),
) )
.apply {
setContentTitle(
notificationDetails?.title
?: getString(R.string.ui_audioRecorder_state_recording_title)
)
setContentText(
notificationDetails?.description
?: getString(R.string.ui_audioRecorder_state_recording_description)
)
setSmallIcon(notificationDetails?.icon ?: R.drawable.launcher_foreground)
setOngoing(notificationDetails?.isOngoing ?: true)
}
.build() .build()
RecorderState.PAUSED -> NotificationCompat.Builder(this, NotificationHelper.RECORDER_CHANNEL_ID)
RecorderState.PAUSED -> NotificationCompat.Builder(
this,
NotificationHelper.RECORDER_CHANNEL_ID
)
.setContentTitle(getString(R.string.ui_audioRecorder_state_paused_title)) .setContentTitle(getString(R.string.ui_audioRecorder_state_paused_title))
.setContentText(getString(R.string.ui_audioRecorder_state_paused_description)) .setContentText(getString(R.string.ui_audioRecorder_state_paused_description))
.setSmallIcon(R.drawable.launcher_foreground) .setSmallIcon(R.drawable.launcher_foreground)
@ -236,6 +260,14 @@ abstract class RecorderService: Service() {
getNotificationChangeStateIntent(RecorderState.RECORDING, 3), getNotificationChangeStateIntent(RecorderState.RECORDING, 3),
) )
.build() .build()
else -> throw IllegalStateException("Invalid state passed to `buildNotification()`") else -> throw IllegalStateException("Invalid state passed to `buildNotification()`")
} }
data class NotificationDetails(
val title: String,
val description: String,
val icon: Int,
val isOngoing: Boolean,
)
} }

View File

@ -18,7 +18,7 @@ import app.myzel394.alibi.enums.RecorderState
import app.myzel394.alibi.services.AudioRecorderService import app.myzel394.alibi.services.AudioRecorderService
import app.myzel394.alibi.services.RecorderService import app.myzel394.alibi.services.RecorderService
class AudioRecorderModel: ViewModel() { class AudioRecorderModel : ViewModel() {
var recorderState by mutableStateOf(RecorderState.IDLE) var recorderState by mutableStateOf(RecorderState.IDLE)
private set private set
var recordingTime by mutableStateOf<Long?>(null) var recordingTime by mutableStateOf<Long?>(null)
@ -48,28 +48,29 @@ class AudioRecorderModel: ViewModel() {
private val connection = object : ServiceConnection { private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) { override fun onServiceConnected(className: ComponentName, service: IBinder) {
recorderService = ((service as RecorderService.RecorderBinder).getService() as AudioRecorderService).also {recorder -> recorderService =
recorder.onStateChange = { state -> ((service as RecorderService.RecorderBinder).getService() as AudioRecorderService).also { recorder ->
recorderState = state recorder.onStateChange = { state ->
} recorderState = state
recorder.onRecordingTimeChange = { time -> }
recordingTime = time recorder.onRecordingTimeChange = { time ->
} recordingTime = time
recorder.onAmplitudeChange = { amps -> }
amplitudes = amps recorder.onAmplitudeChange = { amps ->
onAmplitudeChange() amplitudes = amps
} onAmplitudeChange()
recorder.onError = { }
recorderService!!.createLastRecording() recorder.onError = {
onError() recorderService!!.createLastRecording()
} onError()
}.also { }
it.startRecording() }.also {
it.startRecording()
recorderState = it.state recorderState = it.state
recordingTime = it.recordingTime recordingTime = it.recordingTime
amplitudes = it.amplitudes amplitudes = it.amplitudes
} }
} }
override fun onServiceDisconnected(arg0: ComponentName) { override fun onServiceDisconnected(arg0: ComponentName) {
@ -117,6 +118,10 @@ class AudioRecorderModel: ViewModel() {
recorderService!!.changeState(RecorderState.RECORDING) recorderService!!.changeState(RecorderState.RECORDING)
} }
fun setNotificationDetails(details: RecorderService.NotificationDetails) {
recorderService?.notificationDetails = details
}
fun setMaxAmplitudesAmount(amount: Int) { fun setMaxAmplitudesAmount(amount: Int) {
recorderService?.amplitudesAmount = amount recorderService?.amplitudesAmount = amount
} }