From 5d1812008d1ac1d81d6210c7ec8b1cf66f68d29a Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 24 Nov 2021 15:53:59 +0000 Subject: [PATCH] adding clock abstraction for avoiding directly using the System.currentTimeMillis --- .../im/vector/app/core/di/SingletonModule.kt | 5 ++++ .../java/im/vector/app/core/time/Clock.kt | 29 +++++++++++++++++++ .../home/room/detail/RoomDetailFragment.kt | 8 +++-- .../voice/VoiceMessageRecorderView.kt | 8 ++++- 4 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/core/time/Clock.kt diff --git a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt index 429b88be69..350e1f6b7a 100644 --- a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt @@ -29,6 +29,8 @@ import dagger.hilt.components.SingletonComponent import im.vector.app.core.dispatchers.CoroutineDispatchers import im.vector.app.core.error.DefaultErrorFormatter import im.vector.app.core.error.ErrorFormatter +import im.vector.app.core.time.Clock +import im.vector.app.core.time.DefaultClock import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.invite.CompileTimeAutoAcceptInvites import im.vector.app.features.navigation.DefaultNavigator @@ -66,6 +68,9 @@ abstract class VectorBindModule { @Binds abstract fun bindAutoAcceptInvites(autoAcceptInvites: CompileTimeAutoAcceptInvites): AutoAcceptInvites + + @Binds + abstract fun bindDefaultClock(clock: DefaultClock): Clock } @InstallIn(SingletonComponent::class) diff --git a/vector/src/main/java/im/vector/app/core/time/Clock.kt b/vector/src/main/java/im/vector/app/core/time/Clock.kt new file mode 100644 index 0000000000..ebde7f8fb4 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/time/Clock.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021 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.app.core.time + +import javax.inject.Inject + +interface Clock { + fun epochMillis(): Long +} + +class DefaultClock @Inject constructor() : Clock { + override fun epochMillis(): Long { + return System.currentTimeMillis() + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index 8b506e93c4..08a2e6cd9c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -87,6 +87,7 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.platform.lifecycleAwareLazy import im.vector.app.core.platform.showOptimizedSnackbar import im.vector.app.core.resources.ColorProvider +import im.vector.app.core.time.Clock import im.vector.app.core.ui.views.CurrentCallsView import im.vector.app.core.ui.views.CurrentCallsViewPresenter import im.vector.app.core.ui.views.FailedMessagesWarningView @@ -250,7 +251,8 @@ class RoomDetailFragment @Inject constructor( private val roomDetailPendingActionStore: RoomDetailPendingActionStore, private val pillsPostProcessorFactory: PillsPostProcessor.Factory, private val callManager: WebRtcCallManager, - private val voiceMessagePlaybackTracker: VoiceMessagePlaybackTracker + private val voiceMessagePlaybackTracker: VoiceMessagePlaybackTracker, + private val clock: Clock ) : VectorBaseFragment(), TimelineEventController.Callback, @@ -699,7 +701,7 @@ class RoomDetailFragment @Inject constructor( if (checkPermissions(PERMISSIONS_FOR_VOICE_MESSAGE, requireActivity(), permissionVoiceMessageLauncher)) { messageComposerViewModel.handle(MessageComposerAction.StartRecordingVoiceMessage) vibrate(requireContext()) - updateRecordingUiState(RecordingUiState.Started(System.currentTimeMillis())) + updateRecordingUiState(RecordingUiState.Started(clock.epochMillis())) } } @@ -714,7 +716,7 @@ class RoomDetailFragment @Inject constructor( override fun onVoiceRecordingLocked() { val startedState = withState(messageComposerViewModel) { it.voiceRecordingUiState as? RecordingUiState.Started } - val startTime = startedState?.recordingStartTimestamp ?: System.currentTimeMillis() + val startTime = startedState?.recordingStartTimestamp ?: clock.epochMillis() updateRecordingUiState(RecordingUiState.Locked(startTime)) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceMessageRecorderView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceMessageRecorderView.kt index 3b4c8a58c4..0989337264 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceMessageRecorderView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceMessageRecorderView.kt @@ -20,19 +20,23 @@ import android.content.Context import android.util.AttributeSet import android.view.View import androidx.constraintlayout.widget.ConstraintLayout +import dagger.hilt.android.AndroidEntryPoint import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.extensions.exhaustive import im.vector.app.core.hardware.vibrate +import im.vector.app.core.time.Clock import im.vector.app.core.utils.CountUpTimer import im.vector.app.core.utils.DimensionConverter import im.vector.app.databinding.ViewVoiceMessageRecorderBinding import im.vector.app.features.home.room.detail.timeline.helper.VoiceMessagePlaybackTracker +import javax.inject.Inject import kotlin.math.floor /** * Encapsulates the voice message recording view and animations. */ +@AndroidEntryPoint class VoiceMessageRecorderView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, @@ -51,6 +55,8 @@ class VoiceMessageRecorderView @JvmOverloads constructor( fun onRecordingWaveformClicked() } + @Inject lateinit var clock: Clock + // We need to define views as lateinit var to be able to check if initialized for the bug fix on api 21 and 22. @Suppress("UNNECESSARY_LATEINIT") private lateinit var voiceMessageViews: VoiceMessageViews @@ -163,7 +169,7 @@ class VoiceMessageRecorderView @JvmOverloads constructor( } private fun startRecordingTicker(startFromLocked: Boolean, startAt: Long) { - val startMs = ((System.currentTimeMillis() - startAt)).coerceAtLeast(0) + val startMs = ((clock.epochMillis() - startAt)).coerceAtLeast(0) recordingTicker?.stop() recordingTicker = CountUpTimer().apply { tickListener = object : CountUpTimer.TickListener {