diff --git a/app/src/main/kotlin/com/simplemobiletools/clock/fragments/StopwatchFragment.kt b/app/src/main/kotlin/com/simplemobiletools/clock/fragments/StopwatchFragment.kt index 29de2314..39c8bce2 100644 --- a/app/src/main/kotlin/com/simplemobiletools/clock/fragments/StopwatchFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/clock/fragments/StopwatchFragment.kt @@ -199,13 +199,17 @@ class StopwatchFragment : Fragment() { private val updateListener = object : Stopwatch.UpdateListener { override fun onUpdate(totalTime: Long, lapTime: Long, useLongerMSFormat: Boolean) { - updateDisplayedText(totalTime, lapTime, useLongerMSFormat) + activity?.run { + updateDisplayedText(totalTime, lapTime, useLongerMSFormat) + } } override fun onStateChanged(state: Stopwatch.State) { - updateIcons(state) - binding.stopwatchLap.beVisibleIf(state == Stopwatch.State.RUNNING) - binding.stopwatchReset.beVisibleIf(state != Stopwatch.State.STOPPED) + activity?.run { + updateIcons(state) + binding.stopwatchLap.beVisibleIf(state == Stopwatch.State.RUNNING) + binding.stopwatchReset.beVisibleIf(state != Stopwatch.State.STOPPED) + } } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Stopwatch.kt b/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Stopwatch.kt index 405d7791..47e85f82 100644 --- a/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Stopwatch.kt +++ b/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Stopwatch.kt @@ -1,16 +1,16 @@ package com.simplemobiletools.clock.helpers -import android.os.Handler -import android.os.Looper import android.os.SystemClock import com.simplemobiletools.clock.models.Lap +import java.util.Timer +import java.util.TimerTask import java.util.concurrent.CopyOnWriteArraySet private const val UPDATE_INTERVAL = 10L object Stopwatch { - private val updateHandler = Handler(Looper.getMainLooper()) + private var updateTimer = Timer() private var uptimeAtStart = 0L private var totalTicks = 0 private var currentTicks = 0 // ticks that reset at pause @@ -27,7 +27,7 @@ object Stopwatch { private var updateListeners = CopyOnWriteArraySet() fun reset() { - updateHandler.removeCallbacksAndMessages(null) + updateTimer.cancel() state = State.STOPPED currentTicks = 0 totalTicks = 0 @@ -39,7 +39,7 @@ object Stopwatch { fun toggle(setUptimeAtStart: Boolean) { if (state != State.RUNNING) { state = State.RUNNING - updateHandler.post(updateRunnable) + updateTimer = buildUpdateTimer() if (setUptimeAtStart) { uptimeAtStart = SystemClock.uptimeMillis() } @@ -47,7 +47,7 @@ object Stopwatch { state = State.PAUSED val prevSessionsMS = (totalTicks - currentTicks) * UPDATE_INTERVAL val totalDuration = SystemClock.uptimeMillis() - uptimeAtStart + prevSessionsMS - updateHandler.removeCallbacksAndMessages(null) + updateTimer.cancel() currentTicks = 0 totalTicks-- for (listener in updateListeners) { @@ -97,23 +97,26 @@ object Stopwatch { updateListeners.remove(updateListener) } - private val updateRunnable = object : Runnable { - override fun run() { - if (state == State.RUNNING) { - if (totalTicks % 10 == 0) { - for (listener in updateListeners) { - listener.onUpdate( - totalTicks * UPDATE_INTERVAL, - lapTicks * UPDATE_INTERVAL, - false - ) + private fun buildUpdateTimer(): Timer { + return Timer().apply { + scheduleAtFixedRate(object : TimerTask() { + override fun run() { + if (state == State.RUNNING) { + if (totalTicks % 10 == 0) { + for (listener in updateListeners) { + listener.onUpdate( + totalTicks * UPDATE_INTERVAL, + lapTicks * UPDATE_INTERVAL, + false + ) + } + } + totalTicks++ + currentTicks++ + lapTicks++ } } - totalTicks++ - currentTicks++ - lapTicks++ - updateHandler.postAtTime(this, uptimeAtStart + currentTicks * UPDATE_INTERVAL) - } + }, 0, UPDATE_INTERVAL) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/clock/services/StopwatchService.kt b/app/src/main/kotlin/com/simplemobiletools/clock/services/StopwatchService.kt index ef1d5636..ffb3871c 100644 --- a/app/src/main/kotlin/com/simplemobiletools/clock/services/StopwatchService.kt +++ b/app/src/main/kotlin/com/simplemobiletools/clock/services/StopwatchService.kt @@ -9,6 +9,7 @@ import android.os.Handler import android.os.IBinder import android.os.Looper import androidx.core.app.NotificationCompat +import androidx.core.app.ServiceCompat import androidx.core.content.ContextCompat import com.simplemobiletools.clock.R import com.simplemobiletools.clock.extensions.getFormattedDuration @@ -18,7 +19,6 @@ import com.simplemobiletools.clock.helpers.Stopwatch import com.simplemobiletools.clock.helpers.Stopwatch.State import com.simplemobiletools.clock.helpers.Stopwatch.UpdateListener import com.simplemobiletools.commons.extensions.showErrorToast -import com.simplemobiletools.commons.helpers.isNougatPlus import com.simplemobiletools.commons.helpers.isOreoPlus import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe @@ -54,15 +54,15 @@ class StopwatchService : Service() { } override fun onDestroy() { - super.onDestroy() bus.unregister(this) Stopwatch.removeUpdateListener(updateListener) + super.onDestroy() } @Subscribe(threadMode = ThreadMode.MAIN) fun onMessageEvent(event: StopwatchStopService) { isStopping = true - stopForeground(true) + stopForegroundService() } private fun getServiceNotificationBuilder( @@ -98,17 +98,29 @@ class StopwatchService : Service() { } private val updateListener = object : UpdateListener { + private val MIN_NOTIFICATION_UPDATE_INTERVAL = 500L + private var lastUpdateTime = 0L override fun onUpdate(totalTime: Long, lapTime: Long, useLongerMSFormat: Boolean) { - if (!isStopping) { + if (!isStopping && shouldNotificationBeUpdated()) { + lastUpdateTime = System.currentTimeMillis() updateNotification(totalTime) } } override fun onStateChanged(state: State) { - if (state == State.STOPPED && isNougatPlus()) { - stopForeground(STOP_FOREGROUND_REMOVE) + if (state == State.STOPPED) { + stopForegroundService() } } + + private fun shouldNotificationBeUpdated(): Boolean { + return (System.currentTimeMillis() - lastUpdateTime) > MIN_NOTIFICATION_UPDATE_INTERVAL + } + } + + private fun stopForegroundService() { + ServiceCompat.stopForeground(this@StopwatchService, ServiceCompat.STOP_FOREGROUND_REMOVE) + stopSelf() } }