Pith - wedge_android
wedge_android/app/src/main/java/com/vgmlr/wedge/WedgeAlarmPlayback.kt [5.1 kb]
Modified: 06:16:53 91 026 (18 Jun 026)
6 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.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()
    }
}
Updates
OTC Applet - Linux 93.026.1
Wedge - Linux 90.026.1
Wedge - Android 90.026.1
Shim - Android 86.026.1
Kerf - Android 86.026.4
Dev
TVShow (227) 'CSA'
TVShow (228) 'APT'
TVProgram (83) 'BXT'
Miter Update(s)
Peen (Messaging)

Menu
Calendar
Project Tin (024/029)
Miter
RSS Feed
User Avatar
@vgmlr
=SUM(parts)