Pith - wedge_android
wedge_android/app/src/main/java/com/vgmlr/wedge/WedgeAlarmPlayback.kt [5.9 kb]
Modified: 00:00:28 153 026 (19 Aug 026)
5 Days Ago
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.VibrationAttributes
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)
                        val effect = VibrationEffect.createWaveform(pattern, 1)

                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                            val attrs = VibrationAttributes.Builder()
                                .setUsage(VibrationAttributes.USAGE_ALARM)
                                .build()
                            vib.vibrate(effect, attrs)
                        } else {
                            @Suppress("DEPRECATION")
                            val audioAttrs = android.media.AudioAttributes.Builder()
                                .setUsage(android.media.AudioAttributes.USAGE_ALARM)
                                .setContentType(android.media.AudioAttributes.CONTENT_TYPE_SONIFICATION)
                                .build()
                            @Suppress("DEPRECATION")
                            vib.vibrate(effect, audioAttrs)
                        }
                    }
                }
            } 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()
    }
}
Updates
Kerf - Android 157.026
Kiln - Android 157.026
Wedge - Android 156.026
Whittle - Linux 155.026
Grit - Firefox/Chrome 154.026

Menu
Calendar
Project Tin (024/029)
Miter
RSS Feed
User Avatar
@vgmlr
=SUM(parts)
0.00218
256,877 (+131)