Handle timer service notifications

This commit is contained in:
Paul Akhamiogu
2021-09-01 21:26:56 +01:00
parent 8474e6a800
commit 9b421b3676
36 changed files with 252 additions and 33 deletions

View File

@ -12,10 +12,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.simplemobiletools.clock.R
import com.simplemobiletools.clock.activities.SimpleActivity
import com.simplemobiletools.clock.dialogs.MyTimePickerDialogDialog
import com.simplemobiletools.clock.extensions.checkAlarmsWithDeletedSoundUri
import com.simplemobiletools.clock.extensions.colorLeftDrawable
import com.simplemobiletools.clock.extensions.config
import com.simplemobiletools.clock.extensions.timerHelper
import com.simplemobiletools.clock.extensions.*
import com.simplemobiletools.clock.helpers.PICK_AUDIO_FILE_INTENT_ID
import com.simplemobiletools.clock.models.Timer
import com.simplemobiletools.clock.models.TimerState
@ -116,11 +113,11 @@ class TimerAdapter(
}
is TimerState.Paused -> {
timer_time.text = timer.state.tick.div(1000F).roundToInt().getFormattedDuration()
timer_time.text = timer.state.tick.getFormattedDuration()
}
is TimerState.Running -> {
timer_time.text = timer.state.tick.div(1000F).roundToInt().getFormattedDuration()
timer_time.text = timer.state.tick.getFormattedDuration()
}
}
}
@ -142,9 +139,10 @@ class TimerAdapter(
private fun updateTimer(timer: Timer, refresh: Boolean = true) {
Log.w(TAG, "updateTimer: $timer")
activity.timerHelper.insertOrUpdateTimer(timer)
if (refresh) {
onRefresh.invoke()
activity.timerHelper.insertOrUpdateTimer(timer){
if (refresh) {
onRefresh.invoke()
}
}
}

View File

@ -1,8 +1,10 @@
package com.simplemobiletools.clock.extensions
import android.text.format.DateFormat
import com.simplemobiletools.commons.extensions.getFormattedDuration
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.math.roundToInt
fun Long.formatStopwatchTime(useLongerMSFormat: Boolean): String {
val MSFormat = if (useLongerMSFormat) "%03d" else "%01d"
@ -37,5 +39,9 @@ fun Long.timestampFormat(format: String = "dd. MM. yyyy"): String {
return DateFormat.format(format, calendar).toString()
}
fun Long.getFormattedDuration(forceShowHours: Boolean = false): String {
return this.div(1000F).roundToInt().getFormattedDuration(forceShowHours)
}
val Long.secondsToMillis get() = TimeUnit.SECONDS.toMillis(this)
val Long.millisToSeconds get() = TimeUnit.MILLISECONDS.toSeconds(this)

View File

@ -100,17 +100,24 @@ class TimerFragment : Fragment() {
private fun updateViews(position: Int) {
activity?.runOnUiThread {
val timer = timerAdapter.getItemAt(position)
updateViewStates(timer.state)
if (timerAdapter.itemCount > 0) {
val timer = timerAdapter.getItemAt(position)
updateViewStates(timer.state)
view.timer_play_pause.beVisible()
} else {
view.timer_delete.beGone()
view.timer_play_pause.beGone()
view.timer_reset.beGone()
}
}
}
private fun refreshTimers(scrollToLast: Boolean = false) {
private fun refreshTimers(scrollToLatest: Boolean = false) {
activity?.timerHelper?.getTimers { timers ->
Log.d(TAG, "refreshTimers: $timers")
timerAdapter.submitList(timers) {
if (scrollToLast) {
view.timer_view_pager.currentItem = timers.lastIndex
if (scrollToLatest) {
view.timer_view_pager.currentItem = 0
}
updateViews(timer_view_pager.currentItem)
}

View File

@ -43,14 +43,16 @@ class TimerHelper(val context: Context) {
fun insertNewTimer(callback: () -> Unit = {}) {
ensureBackgroundThread {
timerDao.insertOrUpdateTimer(
Timer(id = null,
Timer(
id = null,
seconds = DEFAULT_TIME,
TimerState.Idle,
false,
context.getDefaultAlarmSound(RingtoneManager.TYPE_ALARM).uri,
context.getDefaultAlarmTitle(RingtoneManager.TYPE_ALARM),
"",
DEFAULT_MAX_TIMER_REMINDER_SECS.toString())
System.currentTimeMillis(),
)
)
callback.invoke()

View File

@ -9,7 +9,7 @@ import com.simplemobiletools.clock.models.Timer
@Dao
interface TimerDao {
@Query("SELECT * FROM timers")
@Query("SELECT * FROM timers ORDER BY createdAt DESC")
fun getTimers(): List<Timer>
@Query("SELECT * FROM timers WHERE id=:id")

View File

@ -12,5 +12,5 @@ data class Timer(
val soundUri: String,
val soundTitle: String,
val label: String,
val maxReminderSecs: String,
val createdAt: Long,
)

View File

@ -12,11 +12,15 @@ import android.os.IBinder
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import com.simplemobiletools.clock.R
import com.simplemobiletools.clock.extensions.config
import com.simplemobiletools.clock.extensions.getFormattedDuration
import com.simplemobiletools.clock.extensions.getOpenTimerTabIntent
import com.simplemobiletools.clock.extensions.timerHelper
import com.simplemobiletools.clock.helpers.TIMER_RUNNING_NOTIF_ID
import com.simplemobiletools.clock.models.TimerEvent
import com.simplemobiletools.clock.models.TimerState
import com.simplemobiletools.commons.extensions.getFormattedDuration
import com.simplemobiletools.commons.helpers.isOreoPlus
import kotlin.math.roundToInt
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
@ -34,18 +38,43 @@ class TimerService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
val formattedDuration = config.timerSeconds.getFormattedDuration()
startForeground(TIMER_RUNNING_NOTIF_ID, notification(formattedDuration))
updateNotification()
startForeground(TIMER_RUNNING_NOTIF_ID, notification(getString(R.string.app_name), getString(R.string.timer_notification_msg), -1))
return START_NOT_STICKY
}
private fun updateNotification() {
timerHelper.getTimers { timers ->
val runningTimers = timers.filter { it.state is TimerState.Running }
if (runningTimers.isNotEmpty()) {
val firstTimer = runningTimers.first()
val formattedDuration = (firstTimer.state as TimerState.Running).tick.getFormattedDuration()
val contextText = when {
runningTimers.size > 1 -> {
getString(R.string.timer_multiple_notification_msg, runningTimers.size)
}
firstTimer.label.isNotEmpty() -> {
getString(R.string.timer_single_notification_label_msg, firstTimer.label)
}
else -> {
getString(R.string.timer_single_notification_msg, runningTimers.size)
}
}
startForeground(TIMER_RUNNING_NOTIF_ID, notification(formattedDuration, contextText, firstTimer.id!!))
}
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(event: TimerStopService) {
stopService()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(event: TimerEvent.Refresh) {
updateNotification()
}
private fun stopService() {
if (isOreoPlus()) {
stopForeground(true)
@ -60,7 +89,7 @@ class TimerService : Service() {
}
@TargetApi(Build.VERSION_CODES.O)
private fun notification(formattedDuration: String): Notification {
private fun notification(title: String, contentText: String, firstRunningTimerId: Long): Notification {
val channelId = "simple_alarm_timer"
val label = getString(R.string.timer)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
@ -73,15 +102,18 @@ class TimerService : Service() {
}
val builder = NotificationCompat.Builder(this)
.setContentTitle(label)
.setContentText(formattedDuration)
.setSmallIcon(R.drawable.ic_timer)
.setContentIntent(this.getOpenTimerTabIntent(0))
.setPriority(Notification.PRIORITY_DEFAULT)
.setSound(null)
.setOngoing(true)
.setAutoCancel(true)
.setChannelId(channelId)
.setContentTitle(title)
.setContentText(contentText)
.setSmallIcon(R.drawable.ic_timer)
.setPriority(Notification.PRIORITY_DEFAULT)
.setSound(null)
.setOngoing(true)
.setAutoCancel(true)
.setChannelId(channelId)
if (firstRunningTimerId != -1L) {
builder.setContentIntent(this.getOpenTimerTabIntent(firstRunningTimerId))
}
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
return builder.build()