package com.vgmlr.wedge
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.media.MediaPlayer
import android.os.Build
import android.os.IBinder
import android.os.VibrationEffect
import android.os.Vibrator
import android.os.VibratorManager
import androidx.core.app.NotificationCompat
import androidx.core.net.toUri
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class WedgeAlarmPlayback : Service() {
private var mediaPlayer: MediaPlayer? = null
private var vibrator: Vibrator? = null
private val serviceJob = Job()
private val serviceScope = CoroutineScope(Dispatchers.Main + serviceJob)
companion object {
private const val CHANNEL_ID = "wedge_alarm"
private const val NOTIFICATION_ID = 3569
private const val ACTION_STOP_ALARM = "com.vgmlr.wedge.ACTION_STOP_ALARM"
}
override fun onBind(intent: Intent?): IBinder? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent?.action == ACTION_STOP_ALARM) {
stopSelf()
return START_NOT_STICKY
}
createNotificationChannel()
val stopIntent = Intent(this, WedgeAlarmPlayback::class.java).apply {
action = ACTION_STOP_ALARM
}
val stopPendingIntent = PendingIntent.getService(
this, 0, stopIntent, PendingIntent.FLAG_IMMUTABLE
)
val eventText = intent?.getStringExtra("ALARM_EVENT_TEXT") ?: "Event Notification"
val notification: Notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Wedge Alarm")
.setContentText(eventText)
.setSmallIcon(android.R.drawable.ic_lock_idle_alarm)
.setOngoing(true)
.setCategory(NotificationCompat.CATEGORY_ALARM)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.addAction(
android.R.drawable.ic_menu_close_clear_cancel,
"Dismiss",
stopPendingIntent
)
.build()
startForeground(NOTIFICATION_ID, notification)
val soundUriStr = intent?.getStringExtra("ALARM_SOUND_URI") ?: ""
val durationMinutes = intent?.getIntExtra("ALARM_DURATION_MINUTES", 5) ?: 5
val vibrationEnabled = intent?.getBooleanExtra("ALARM_VIBRATION_ENABLED", false) ?: false
try {
mediaPlayer?.release()
mediaPlayer = MediaPlayer().apply {
setAudioAttributes(
android.media.AudioAttributes.Builder()
.setUsage(android.media.AudioAttributes.USAGE_ALARM)
.setContentType(android.media.AudioAttributes.CONTENT_TYPE_MUSIC)
.build()
)
if (soundUriStr.isNotEmpty()) {
setDataSource(applicationContext, soundUriStr.toUri())
} else {
val defaultAlarmUri = android.media.RingtoneManager.getDefaultUri(android.media.RingtoneManager.TYPE_ALARM)
setDataSource(applicationContext, defaultAlarmUri)
}
isLooping = true
prepare()
start()
}
} catch (e: Exception) {
e.printStackTrace()
}
if (vibrationEnabled) {
try {
vibrator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val vibratorManager = getSystemService(VIBRATOR_MANAGER_SERVICE) as VibratorManager
vibratorManager.defaultVibrator
} else {
@Suppress("DEPRECATION")
getSystemService(VIBRATOR_SERVICE) as Vibrator
}
vibrator?.let { vib ->
if (vib.hasVibrator()) {
val pattern = longArrayOf(0, 500, 500)
vib.vibrate(VibrationEffect.createWaveform(pattern, 1))
}
}
} catch (_: Exception) {}
}
serviceScope.launch {
delay(durationMinutes * 60 * 1000L)
stopSelf()
}
return START_NOT_STICKY
}
private fun createNotificationChannel() {
val channel = NotificationChannel(
CHANNEL_ID,
"Wedge Alarms",
NotificationManager.IMPORTANCE_HIGH
).apply {
description = "Alarm for identified events"
setSound(null, null)
}
val manager = getSystemService(NotificationManager::class.java)
manager.createNotificationChannel(channel)
}
override fun onDestroy() {
super.onDestroy()
mediaPlayer?.stop()
mediaPlayer?.release()
mediaPlayer = null
vibrator?.cancel()
vibrator = null
serviceJob.cancel()
}
}