Skip to content

Instantly share code, notes, and snippets.

@ziginsider
Created July 9, 2021 22:03
Show Gist options
  • Save ziginsider/bd62f64cd1e75f6354ee8344854d399c to your computer and use it in GitHub Desktop.
Save ziginsider/bd62f64cd1e75f6354ee8344854d399c to your computer and use it in GitHub Desktop.
class ForegroundService : Service() {
private var isServiceStarted = false
private var notificationManager: NotificationManager? = null
private var job: Job? = null
private val builder by lazy {
NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Simple Timer")
.setGroup("Timer")
.setGroupSummary(false)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(getPendingIntent())
.setSilent(true)
.setSmallIcon(R.drawable.ic_baseline_access_alarm_24)
}
override fun onCreate() {
super.onCreate()
notificationManager =
applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
processCommand(intent)
return START_REDELIVER_INTENT
}
override fun onBind(intent: Intent): IBinder? {
return null
}
private fun processCommand(intent: Intent?) {
when (intent?.extras?.getString(COMMAND_ID) ?: INVALID) {
COMMAND_START -> {
val startTime = intent?.extras?.getLong(STARTED_TIMER_TIME_MS) ?: return
commandStart(startTime)
}
COMMAND_STOP -> commandStop()
INVALID -> return
}
}
private fun commandStart(startTime: Long) {
if (isServiceStarted) {
return
}
Log.i("TAG", "commandStart()")
try {
moveToStartedState()
startForegroundAndShowNotification()
continueTimer(startTime)
} finally {
isServiceStarted = true
}
}
private fun continueTimer(startTime: Long) {
job = GlobalScope.launch(Dispatchers.Main) {
while (true) {
notificationManager?.notify(
NOTIFICATION_ID,
getNotification(
(System.currentTimeMillis() - startTime).displayTime().dropLast(3)
)
)
delay(INTERVAL)
}
}
}
private fun commandStop() {
if (!isServiceStarted) {
return
}
Log.i("TAG", "commandStop()")
try {
job?.cancel()
stopForeground(true)
stopSelf()
} finally {
isServiceStarted = false
}
}
private fun moveToStartedState() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Log.d("TAG", "moveToStartedState(): Running on Android O or higher")
startForegroundService(Intent(this, ForegroundService::class.java))
} else {
Log.d("TAG", "moveToStartedState(): Running on Android N or lower")
startService(Intent(this, ForegroundService::class.java))
}
}
private fun startForegroundAndShowNotification() {
createChannel()
val notification = getNotification("content")
startForeground(NOTIFICATION_ID, notification)
}
private fun getNotification(content: String) = builder.setContentText(content).build()
private fun createChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelName = "pomodoro"
val importance = NotificationManager.IMPORTANCE_DEFAULT
val notificationChannel = NotificationChannel(
CHANNEL_ID, channelName, importance
)
notificationManager?.createNotificationChannel(notificationChannel)
}
}
private fun getPendingIntent(): PendingIntent? {
val resultIntent = Intent(this, MainActivity::class.java)
resultIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
return PendingIntent.getActivity(this, 0, resultIntent, PendingIntent.FLAG_ONE_SHOT)
}
private companion object {
private const val CHANNEL_ID = "Channel_ID"
private const val NOTIFICATION_ID = 777
private const val INTERVAL = 1000L
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment