From bdfebac76d4dbd14048a9cb7435d6c57cdac8804 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Fri, 27 Jan 2023 17:49:55 +0100 Subject: [PATCH] CountUpTimer - compute elapsed time using real time --- .../im/vector/lib/core/utils/timer/Clock.kt | 34 +++++++++++++++++++ .../lib/core/utils/timer/CountUpTimer.kt | 23 ++++++++----- 2 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 library/core-utils/src/main/java/im/vector/lib/core/utils/timer/Clock.kt diff --git a/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/Clock.kt b/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/Clock.kt new file mode 100644 index 0000000000..47e2c6532a --- /dev/null +++ b/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/Clock.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.lib.core.utils.timer + +interface Clock { + fun epochMillis(): Long +} + +class DefaultClock : Clock { + + /** + * Provides a UTC epoch in milliseconds + * + * This value is not guaranteed to be correct with reality + * as a User can override the system time and date to any values. + */ + override fun epochMillis(): Long { + return System.currentTimeMillis() + } +} diff --git a/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/CountUpTimer.kt b/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/CountUpTimer.kt index 297e33d9cc..debb1d0f4b 100644 --- a/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/CountUpTimer.kt +++ b/library/core-utils/src/main/java/im/vector/lib/core/utils/timer/CountUpTimer.kt @@ -28,22 +28,23 @@ import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicLong @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) -class CountUpTimer(private val initialTime: Long = 0L, private val intervalInMs: Long = 1_000) { +class CountUpTimer(initialTime: Long = 0L, private val intervalInMs: Long = 1_000) { private val coroutineScope = CoroutineScope(Dispatchers.Main) - private val elapsedTime: AtomicLong = AtomicLong(initialTime) private val resumed: AtomicBoolean = AtomicBoolean(false) + private val clock: Clock = DefaultClock() + private var lastTime: AtomicLong = AtomicLong() + private val elapsedTime: AtomicLong = AtomicLong(initialTime) + init { startCounter() } private fun startCounter() { - val internalDelay = if (intervalInMs > 100) intervalInMs / 10 else intervalInMs - tickerFlow(coroutineScope, internalDelay) + tickerFlow(coroutineScope, intervalInMs) .filter { resumed.get() } - .map { elapsedTime.addAndGet(internalDelay) } - .filter { (it - initialTime) % intervalInMs == 0L } + .map { addAndGetElapsedTime() } .onEach { tickListener?.onTick(it) } .launchIn(coroutineScope) } @@ -55,19 +56,25 @@ class CountUpTimer(private val initialTime: Long = 0L, private val intervalInMs: } fun pause() { - tickListener?.onTick(elapsedTime()) + tickListener?.onTick(addAndGetElapsedTime()) resumed.set(false) } fun resume() { + lastTime.set(clock.epochMillis()) resumed.set(true) } fun stop() { - tickListener?.onTick(elapsedTime()) + tickListener?.onTick(addAndGetElapsedTime()) coroutineScope.cancel() } + private fun addAndGetElapsedTime(): Long { + val now = clock.epochMillis() + return elapsedTime.addAndGet(now - lastTime.getAndSet(now)) + } + fun interface TickListener { fun onTick(milliseconds: Long) }