156 lines
5.9 KiB
Kotlin
156 lines
5.9 KiB
Kotlin
package com.massive
|
|
|
|
import android.Manifest
|
|
import android.annotation.SuppressLint
|
|
import android.app.*
|
|
import android.content.BroadcastReceiver
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.content.IntentFilter
|
|
import android.content.pm.PackageManager
|
|
import android.os.*
|
|
import android.util.Log
|
|
import androidx.core.app.ActivityCompat
|
|
import androidx.core.app.NotificationCompat
|
|
import androidx.core.app.NotificationManagerCompat
|
|
|
|
class TimerService : Service() {
|
|
|
|
private lateinit var timerHandler: Handler
|
|
private var timerRunnable: Runnable? = null
|
|
private var timeLeftInSeconds: Int = 0
|
|
private var timeTotalInSeconds: Int = 0
|
|
private var notificationId = 1
|
|
|
|
private val stopReceiver =
|
|
object : BroadcastReceiver() {
|
|
override fun onReceive(context: Context?, intent: Intent?) {
|
|
Log.d("TimerService", "Received stop broadcast intent")
|
|
stopSelf()
|
|
}
|
|
}
|
|
|
|
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
|
override fun onCreate() {
|
|
super.onCreate()
|
|
timerHandler = Handler(Looper.getMainLooper())
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
applicationContext.registerReceiver(stopReceiver, IntentFilter(STOP_BROADCAST),
|
|
Context.RECEIVER_NOT_EXPORTED)
|
|
}
|
|
else {
|
|
applicationContext.registerReceiver(stopReceiver, IntentFilter(STOP_BROADCAST))
|
|
}
|
|
}
|
|
|
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
|
timeLeftInSeconds = (intent?.getIntExtra("milliseconds", 0) ?: 0) / 1000
|
|
startForeground(notificationId, createNotification(timeLeftInSeconds))
|
|
Log.d("TimerService", "onStartCommand seconds=$timeLeftInSeconds")
|
|
timeTotalInSeconds = timeLeftInSeconds
|
|
|
|
timerRunnable = object : Runnable {
|
|
override fun run() {
|
|
if (timeLeftInSeconds > 0) {
|
|
timeLeftInSeconds--
|
|
updateNotification(timeLeftInSeconds)
|
|
timerHandler.postDelayed(this, 1000)
|
|
} else {
|
|
startAlarmService()
|
|
stopSelf()
|
|
}
|
|
}
|
|
}
|
|
timerHandler.postDelayed(timerRunnable!!, 1000)
|
|
return START_STICKY
|
|
}
|
|
|
|
override fun onDestroy() {
|
|
super.onDestroy()
|
|
timerHandler.removeCallbacks(timerRunnable!!)
|
|
applicationContext.unregisterReceiver(stopReceiver)
|
|
}
|
|
|
|
override fun onBind(intent: Intent?): IBinder? {
|
|
return null
|
|
}
|
|
|
|
private fun createNotification(timeLeftInSeconds: Int): Notification {
|
|
val notificationTitle = "Timer"
|
|
val notificationText = formatTime(timeLeftInSeconds)
|
|
val notificationChannelId = "timer_channel"
|
|
val notificationIntent = Intent(this, TimerService::class.java)
|
|
val pendingIntent = PendingIntent.getActivity(
|
|
this,
|
|
0,
|
|
notificationIntent,
|
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
|
)
|
|
val stopBroadcast = Intent(AlarmModule.STOP_BROADCAST)
|
|
stopBroadcast.setPackage(applicationContext.packageName)
|
|
val pendingStop =
|
|
PendingIntent.getBroadcast(applicationContext, 0, stopBroadcast, PendingIntent.FLAG_IMMUTABLE)
|
|
|
|
val notificationBuilder = NotificationCompat.Builder(this, notificationChannelId)
|
|
.setContentTitle(notificationTitle)
|
|
.setContentText(notificationText)
|
|
.setSmallIcon(R.drawable.ic_baseline_timer_24)
|
|
.setProgress(timeTotalInSeconds, timeLeftInSeconds, false)
|
|
.setContentIntent(pendingIntent)
|
|
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
|
|
.setAutoCancel(false)
|
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
|
.setPriority(NotificationCompat.PRIORITY_LOW)
|
|
.setOngoing(true)
|
|
.setDeleteIntent(pendingStop)
|
|
.addAction(R.drawable.ic_baseline_stop_24, "Stop", pendingStop)
|
|
|
|
val notificationManager = NotificationManagerCompat.from(this)
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
val channel = NotificationChannel(
|
|
notificationChannelId,
|
|
"Timer Channel",
|
|
NotificationManager.IMPORTANCE_LOW
|
|
)
|
|
notificationManager.createNotificationChannel(channel)
|
|
}
|
|
|
|
return notificationBuilder.build()
|
|
}
|
|
|
|
private fun updateNotification(timeLeftInSeconds: Int) {
|
|
val notificationManager = NotificationManagerCompat.from(this)
|
|
val notification = createNotification(timeLeftInSeconds)
|
|
if (ActivityCompat.checkSelfPermission(
|
|
this,
|
|
Manifest.permission.POST_NOTIFICATIONS
|
|
) != PackageManager.PERMISSION_GRANTED
|
|
) {
|
|
// TODO: Consider calling
|
|
// ActivityCompat#requestPermissions
|
|
// here to request the missing permissions, and then overriding
|
|
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
|
|
// int[] grantResults)
|
|
// to handle the case where the user grants the permission. See the documentation
|
|
// for ActivityCompat#requestPermissions for more details.
|
|
return
|
|
}
|
|
notificationManager.notify(notificationId, notification)
|
|
}
|
|
|
|
private fun formatTime(timeInSeconds: Int): String {
|
|
val minutes = timeInSeconds / 60
|
|
val seconds = timeInSeconds % 60
|
|
return String.format("%02d:%02d", minutes, seconds)
|
|
}
|
|
|
|
private fun startAlarmService() {
|
|
val intent = Intent(applicationContext, AlarmService::class.java)
|
|
applicationContext.startService(intent)
|
|
}
|
|
|
|
companion object {
|
|
const val STOP_BROADCAST = "stop-timer-event"
|
|
}
|
|
}
|