From 40d3203297a02c6a3091671707ee3871aec930fd Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 3 May 2022 10:32:48 +0200 Subject: [PATCH] Use Clock interface app side --- .../java/im/vector/app/EspressoExt.kt | 12 ++-- .../java/im/vector/app/RegistrationTest.kt | 3 +- .../im/vector/app/SecurityBootstrapTest.kt | 3 +- .../app/VerifySessionInteractiveTest.kt | 3 +- .../vector/app/VerifySessionPassphraseTest.kt | 3 +- .../espresso/tools/ScreenshotFailureRule.kt | 3 +- .../app/features/debug/DebugMenuActivity.kt | 17 +++-- .../receiver/AlarmSyncBroadcastReceiver.kt | 2 +- .../app/core/date/VectorDateFormatter.kt | 15 +++-- .../dialogs/GalleryOrCameraDialogHelper.kt | 6 +- .../app/core/services/VectorSyncService.kt | 31 ++++++--- .../core/utils/ExternalApplicationsUtil.kt | 32 ++++++--- .../preview/AttachmentsPreviewFragment.kt | 6 +- .../features/call/conference/JitsiService.kt | 7 +- .../call/webrtc/ScreenCaptureService.kt | 4 +- .../setup/KeysBackupSetupSharedViewModel.kt | 13 ++-- .../IncomingVerificationRequestHandler.kt | 9 ++- .../UnknownDeviceDetectorSharedViewModel.kt | 14 ++-- .../home/room/detail/ChatEffectManager.kt | 7 +- .../detail/RoomMessageTouchHelperCallback.kt | 12 ++-- .../home/room/detail/TimelineFragment.kt | 7 +- .../composer/MessageComposerViewState.kt | 6 +- .../detail/search/SearchResultController.kt | 9 ++- .../timeline/TimelineEventController.kt | 67 ++++++++++++------- .../ViewEditHistoryEpoxyController.kt | 6 +- .../TimelineControllerInterceptorHelper.kt | 5 +- .../login2/created/AccountCreatedFragment.kt | 6 +- .../domain/usecase/DownloadMediaUseCase.kt | 7 +- .../notifications/NotifiableEventResolver.kt | 18 +++-- .../NotificationBroadcastReceiver.kt | 6 +- .../notifications/NotificationUtils.kt | 36 +++++----- .../FtueAuthChooseProfilePictureFragment.kt | 6 +- .../app/features/popup/PopupAlertManager.kt | 9 ++- .../createroom/CreateRoomFragment.kt | 9 ++- .../settings/RoomSettingsFragment.kt | 9 ++- .../uploads/RoomUploadsFragment.kt | 7 +- .../features/settings/VectorPreferences.kt | 24 ++++--- .../settings/VectorSettingsGeneralFragment.kt | 6 +- .../settings/devtools/KeyRequestsFragment.kt | 7 +- .../create/CreateSpaceDetailsFragment.kt | 6 +- .../spaces/manage/SpaceSettingsFragment.kt | 11 +-- .../userdirectory/UserListViewModel.kt | 3 +- .../app/features/voice/VoicePlayerHelper.kt | 6 +- .../app/features/voice/VoiceRecorderL.kt | 10 ++- .../features/voice/VoiceRecorderProvider.kt | 6 +- 45 files changed, 320 insertions(+), 174 deletions(-) diff --git a/vector/src/androidTest/java/im/vector/app/EspressoExt.kt b/vector/src/androidTest/java/im/vector/app/EspressoExt.kt index 35554ae75a..899f268176 100644 --- a/vector/src/androidTest/java/im/vector/app/EspressoExt.kt +++ b/vector/src/androidTest/java/im/vector/app/EspressoExt.kt @@ -43,6 +43,7 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialogFragment import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.core.time.DefaultClock import im.vector.app.espresso.tools.waitUntilViewVisible import org.hamcrest.Matcher import org.hamcrest.Matchers @@ -52,6 +53,7 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.PrivateKeysInfo import org.matrix.android.sdk.api.session.sync.SyncState import org.matrix.android.sdk.api.util.Optional import java.util.concurrent.TimeoutException +import kotlin.random.Random object EspressoHelper { fun getCurrentActivity(): Activity? { @@ -89,6 +91,8 @@ fun getString(@StringRes id: Int): String { fun waitForView(viewMatcher: Matcher, timeout: Long = 10_000, waitForDisplayed: Boolean = true): ViewAction { return object : ViewAction { + private val clock = DefaultClock() + override fun getConstraints(): Matcher { return Matchers.any(View::class.java) } @@ -102,14 +106,14 @@ fun waitForView(viewMatcher: Matcher, timeout: Long = 10_000, waitForDispl override fun perform(uiController: UiController, view: View) { println("*** waitForView 1 $view") uiController.loopMainThreadUntilIdle() - val startTime = System.currentTimeMillis() + val startTime = clock.epochMillis() val endTime = startTime + timeout val visibleMatcher = isDisplayed() uiController.loopMainThreadForAtLeast(100) do { - println("*** waitForView loop $view end:$endTime current:${System.currentTimeMillis()}") + println("*** waitForView loop $view end:$endTime current:${clock.epochMillis()}") val viewVisible = TreeIterables.breadthFirstViewTraversal(view) .any { viewMatcher.matches(it) && visibleMatcher.matches(it) } @@ -118,7 +122,7 @@ fun waitForView(viewMatcher: Matcher, timeout: Long = 10_000, waitForDispl println("*** waitForView loop loopMainThreadForAtLeast...") uiController.loopMainThreadForAtLeast(50) println("*** waitForView loop ...loopMainThreadForAtLeast") - } while (System.currentTimeMillis() < endTime) + } while (clock.epochMillis() < endTime) println("*** waitForView timeout $view") // Timeout happens. @@ -168,7 +172,7 @@ fun activityIdlingResource(activityClass: Class<*>): IdlingResource { val res = object : IdlingResource, ActivityLifecycleCallback { private var callback: IdlingResource.ResourceCallback? = null private var resumedActivity: Activity? = null - private val uniqTS = System.currentTimeMillis() + private val uniqTS = Random.nextLong() override fun getName() = "activityIdlingResource_${activityClass.name}_$uniqTS" diff --git a/vector/src/androidTest/java/im/vector/app/RegistrationTest.kt b/vector/src/androidTest/java/im/vector/app/RegistrationTest.kt index fcec2a9fb5..344a2ecfb1 100644 --- a/vector/src/androidTest/java/im/vector/app/RegistrationTest.kt +++ b/vector/src/androidTest/java/im/vector/app/RegistrationTest.kt @@ -34,6 +34,7 @@ import org.hamcrest.CoreMatchers.not import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import kotlin.random.Random @RunWith(AndroidJUnit4::class) @LargeTest @@ -44,7 +45,7 @@ class RegistrationTest { @Test fun simpleRegister() { - val userId: String = "UiAutoTest_${System.currentTimeMillis()}" + val userId: String = "UiAutoTest_${Random.nextLong()}" val password: String = "password" val homeServerUrl: String = "http://10.0.2.2:8080" diff --git a/vector/src/androidTest/java/im/vector/app/SecurityBootstrapTest.kt b/vector/src/androidTest/java/im/vector/app/SecurityBootstrapTest.kt index a84aae9994..21fd226317 100644 --- a/vector/src/androidTest/java/im/vector/app/SecurityBootstrapTest.kt +++ b/vector/src/androidTest/java/im/vector/app/SecurityBootstrapTest.kt @@ -48,6 +48,7 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.matrix.android.sdk.api.session.Session +import kotlin.random.Random @RunWith(AndroidJUnit4::class) @LargeTest @@ -61,7 +62,7 @@ class SecurityBootstrapTest : VerificationTestBase() { @Before fun createSessionWithCrossSigning() { val matrix = getMatrixInstance() - val userName = "foobar_${System.currentTimeMillis()}" + val userName = "foobar_${Random.nextLong()}" existingSession = createAccountAndSync(matrix, userName, password, true) stubAllExternalIntents() } diff --git a/vector/src/androidTest/java/im/vector/app/VerifySessionInteractiveTest.kt b/vector/src/androidTest/java/im/vector/app/VerifySessionInteractiveTest.kt index c82b543a08..76f09638be 100644 --- a/vector/src/androidTest/java/im/vector/app/VerifySessionInteractiveTest.kt +++ b/vector/src/androidTest/java/im/vector/app/VerifySessionInteractiveTest.kt @@ -53,6 +53,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransa import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState import kotlin.coroutines.Continuation import kotlin.coroutines.resume +import kotlin.random.Random @RunWith(AndroidJUnit4::class) @LargeTest @@ -66,7 +67,7 @@ class VerifySessionInteractiveTest : VerificationTestBase() { @Before fun createSessionWithCrossSigning() { val matrix = getMatrixInstance() - val userName = "foobar_${System.currentTimeMillis()}" + val userName = "foobar_${Random.nextLong()}" existingSession = createAccountAndSync(matrix, userName, password, true) doSync { existingSession!!.cryptoService().crossSigningService() diff --git a/vector/src/androidTest/java/im/vector/app/VerifySessionPassphraseTest.kt b/vector/src/androidTest/java/im/vector/app/VerifySessionPassphraseTest.kt index 80d8315a0e..76d5717000 100644 --- a/vector/src/androidTest/java/im/vector/app/VerifySessionPassphraseTest.kt +++ b/vector/src/androidTest/java/im/vector/app/VerifySessionPassphraseTest.kt @@ -53,6 +53,7 @@ import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.session.Session import kotlin.coroutines.Continuation import kotlin.coroutines.resume +import kotlin.random.Random @RunWith(AndroidJUnit4::class) @LargeTest @@ -68,7 +69,7 @@ class VerifySessionPassphraseTest : VerificationTestBase() { fun createSessionWithCrossSigningAnd4S() { val context = InstrumentationRegistry.getInstrumentation().targetContext val matrix = getMatrixInstance() - val userName = "foobar_${System.currentTimeMillis()}" + val userName = "foobar_${Random.nextLong()}" existingSession = createAccountAndSync(matrix, userName, password, true) doSync { existingSession!!.cryptoService().crossSigningService() diff --git a/vector/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt b/vector/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt index 2939dcf4e0..b01c1a895f 100644 --- a/vector/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt +++ b/vector/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt @@ -24,6 +24,7 @@ import android.os.Build import android.os.Environment import android.provider.MediaStore import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation +import im.vector.app.core.time.DefaultClock import org.junit.rules.TestWatcher import org.junit.runner.Description import timber.log.Timber @@ -54,7 +55,7 @@ private fun storeFailureScreenshot(bitmap: Bitmap, screenshotName: String) { val contentValues = ContentValues().apply { put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") - put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis()) + put(MediaStore.Images.Media.DATE_TAKEN, DefaultClock().epochMillis()) } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { useMediaStoreScreenshotStorage( diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt index cc69cfd426..07b7c9ebf9 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt @@ -29,6 +29,7 @@ import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.core.time.Clock import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO import im.vector.app.core.utils.checkPermissions import im.vector.app.core.utils.registerForPermissionsResult @@ -59,6 +60,8 @@ class DebugMenuActivity : VectorBaseActivity() { @Inject lateinit var activeSessionHolder: ActiveSessionHolder + @Inject + lateinit var clock: Clock private lateinit var buffer: ByteArray @@ -165,7 +168,7 @@ class DebugMenuActivity : VectorBaseActivity() { } val builder = NotificationCompat.Builder(this, "CHAN") - .setWhen(System.currentTimeMillis()) + .setWhen(clock.epochMillis()) .setContentTitle("Title") .setContentText("Content") // No effect because it's a group summary notif @@ -180,16 +183,16 @@ class DebugMenuActivity : VectorBaseActivity() { .setName("User name") .build() ) - .addMessage("Message 1 - 1", System.currentTimeMillis(), Person.Builder().setName("user 1-1").build()) - .addMessage("Message 1 - 2", System.currentTimeMillis(), Person.Builder().setName("user 1-2").build()) + .addMessage("Message 1 - 1", clock.epochMillis(), Person.Builder().setName("user 1-1").build()) + .addMessage("Message 1 - 2", clock.epochMillis(), Person.Builder().setName("user 1-2").build()) val messagingStyle2 = NotificationCompat.MessagingStyle( Person.Builder() .setName("User name 2") .build() ) - .addMessage("Message 2 - 1", System.currentTimeMillis(), Person.Builder().setName("user 1-1").build()) - .addMessage("Message 2 - 2", System.currentTimeMillis(), Person.Builder().setName("user 1-2").build()) + .addMessage("Message 2 - 1", clock.epochMillis(), Person.Builder().setName("user 1-1").build()) + .addMessage("Message 2 - 2", clock.epochMillis(), Person.Builder().setName("user 1-2").build()) notificationManager.notify(10, builder.build()) @@ -197,7 +200,7 @@ class DebugMenuActivity : VectorBaseActivity() { 11, NotificationCompat.Builder(this, "CHAN") .setChannelId("CHAN") - .setWhen(System.currentTimeMillis()) + .setWhen(clock.epochMillis()) .setContentTitle("Title 1") .setContentText("Content 1") // For shortcut on long press on launcher icon @@ -211,7 +214,7 @@ class DebugMenuActivity : VectorBaseActivity() { notificationManager.notify( 12, NotificationCompat.Builder(this, "CHAN2") - .setWhen(System.currentTimeMillis()) + .setWhen(clock.epochMillis()) .setContentTitle("Title 2") .setContentText("Content 2") .setStyle(messagingStyle2) diff --git a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt index 4be36d7de3..a847f8fc45 100644 --- a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt +++ b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/AlarmSyncBroadcastReceiver.kt @@ -74,7 +74,7 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() { intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE ) - val firstMillis = System.currentTimeMillis() + delayInSeconds * 1000L + val firstMillis = clock.epochMillis() + delayInSeconds * 1000L val alarmMgr = context.getSystemService()!! if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pIntent) diff --git a/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt b/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt index eb6f6a94f7..029fce7423 100644 --- a/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt +++ b/vector/src/main/java/im/vector/app/core/date/VectorDateFormatter.kt @@ -22,15 +22,19 @@ import android.text.format.DateUtils import im.vector.app.core.resources.DateProvider import im.vector.app.core.resources.LocaleProvider import im.vector.app.core.resources.toTimestamp +import im.vector.app.core.time.Clock import org.threeten.bp.LocalDateTime import org.threeten.bp.Period import org.threeten.bp.format.DateTimeFormatter import javax.inject.Inject import kotlin.math.absoluteValue -class VectorDateFormatter @Inject constructor(private val context: Context, - private val localeProvider: LocaleProvider, - private val dateFormatterProviders: DateFormatterProviders) { +class VectorDateFormatter @Inject constructor( + private val context: Context, + private val localeProvider: LocaleProvider, + private val dateFormatterProviders: DateFormatterProviders, + private val clock: Clock, +) { private val hourFormatter by lazy { if (DateFormat.is24HourFormat(context)) { @@ -158,8 +162,9 @@ class VectorDateFormatter @Inject constructor(private val context: Context, private fun getRelativeDay(ts: Long): String { return DateUtils.getRelativeTimeSpanString( ts, - System.currentTimeMillis(), + clock.epochMillis(), DateUtils.DAY_IN_MILLIS, - DateUtils.FORMAT_SHOW_WEEKDAY).toString() + DateUtils.FORMAT_SHOW_WEEKDAY + ).toString() } } diff --git a/vector/src/main/java/im/vector/app/core/dialogs/GalleryOrCameraDialogHelper.kt b/vector/src/main/java/im/vector/app/core/dialogs/GalleryOrCameraDialogHelper.kt index 8f70808087..757b415ce5 100644 --- a/vector/src/main/java/im/vector/app/core/dialogs/GalleryOrCameraDialogHelper.kt +++ b/vector/src/main/java/im/vector/app/core/dialogs/GalleryOrCameraDialogHelper.kt @@ -27,6 +27,7 @@ import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper.Listener import im.vector.app.core.extensions.insertBeforeLast import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.resources.ColorProvider +import im.vector.app.core.time.Clock import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO import im.vector.app.core.utils.checkPermissions import im.vector.app.core.utils.onPermissionDeniedDialog @@ -45,7 +46,8 @@ import java.io.File class GalleryOrCameraDialogHelper( // must implement GalleryOrCameraDialogHelper.Listener private val fragment: Fragment, - private val colorProvider: ColorProvider + private val colorProvider: ColorProvider, + private val clock: Clock, ) { interface Listener { fun onImageReady(uri: Uri?) @@ -91,7 +93,7 @@ class GalleryOrCameraDialogHelper( } private fun startUCrop(image: MultiPickerImageType) { - val destinationFile = File(activity.cacheDir, image.displayName.insertBeforeLast("_e_${System.currentTimeMillis()}")) + val destinationFile = File(activity.cacheDir, image.displayName.insertBeforeLast("_e_${clock.epochMillis()}")) val uri = image.contentUri createUCropWithDefaultSettings(colorProvider, uri, destinationFile.toUri(), fragment.getString(R.string.rotate_and_crop_screen_title)) .withAspectRatio(1f, 1f) diff --git a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt index 5dbea8dcc4..8051900bcb 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorSyncService.kt @@ -33,6 +33,8 @@ import androidx.work.WorkerParameters import dagger.hilt.android.AndroidEntryPoint import im.vector.app.R import im.vector.app.core.platform.PendingIntentCompat +import im.vector.app.core.time.Clock +import im.vector.app.core.time.DefaultClock import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.settings.BackgroundSyncMode import org.matrix.android.sdk.api.Matrix @@ -77,6 +79,7 @@ class VectorSyncService : SyncService() { @Inject lateinit var notificationUtils: NotificationUtils @Inject lateinit var matrix: Matrix + @Inject lateinit var clock: Clock override fun provideMatrix() = matrix @@ -102,7 +105,8 @@ class VectorSyncService : SyncService() { syncTimeoutSeconds = syncTimeoutSeconds, syncDelaySeconds = syncDelaySeconds, isPeriodic = true, - isNetworkBack = false + isNetworkBack = false, + now = clock.epochMillis() ) } @@ -114,9 +118,10 @@ class VectorSyncService : SyncService() { val rescheduleSyncWorkRequest: WorkRequest = OneTimeWorkRequestBuilder() .setInputData(RestartWhenNetworkOn.createInputData(sessionId, syncTimeoutSeconds, syncDelaySeconds, isPeriodic)) - .setConstraints(Constraints.Builder() - .setRequiredNetworkType(NetworkType.CONNECTED) - .build() + .setConstraints( + Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() ) .build() @@ -137,20 +142,27 @@ class VectorSyncService : SyncService() { } // I do not move or rename this class, since I'm not sure about the side effect regarding the WorkManager - class RestartWhenNetworkOn(appContext: Context, workerParams: WorkerParameters) : - Worker(appContext, workerParams) { + class RestartWhenNetworkOn( + appContext: Context, + workerParams: WorkerParameters + ) : Worker(appContext, workerParams) { + override fun doWork(): Result { Timber.d("## Sync: RestartWhenNetworkOn.doWork()") val sessionId = inputData.getString(KEY_SESSION_ID) ?: return Result.failure() val syncTimeoutSeconds = inputData.getInt(KEY_SYNC_TIMEOUT_SECONDS, BackgroundSyncMode.DEFAULT_SYNC_TIMEOUT_SECONDS) val syncDelaySeconds = inputData.getInt(KEY_SYNC_DELAY_SECONDS, BackgroundSyncMode.DEFAULT_SYNC_DELAY_SECONDS) val isPeriodic = inputData.getBoolean(KEY_IS_PERIODIC, false) + + // Not sure how to inject a Clock here + val clock = DefaultClock() applicationContext.rescheduleSyncService( sessionId = sessionId, syncTimeoutSeconds = syncTimeoutSeconds, syncDelaySeconds = syncDelaySeconds, isPeriodic = isPeriodic, - isNetworkBack = true + isNetworkBack = true, + now = clock.epochMillis() ) // Indicate whether the work finished successfully with the Result return Result.success() @@ -182,7 +194,8 @@ private fun Context.rescheduleSyncService(sessionId: String, syncTimeoutSeconds: Int, syncDelaySeconds: Int, isPeriodic: Boolean, - isNetworkBack: Boolean) { + isNetworkBack: Boolean, + now: Long) { Timber.d("## Sync: rescheduleSyncService") val intent = if (isPeriodic) { VectorSyncService.newPeriodicIntent( @@ -208,7 +221,7 @@ private fun Context.rescheduleSyncService(sessionId: String, } else { PendingIntent.getService(this, 0, intent, PendingIntentCompat.FLAG_IMMUTABLE) } - val firstMillis = System.currentTimeMillis() + syncDelaySeconds * 1000L + val firstMillis = now + syncDelaySeconds * 1000L val alarmMgr = getSystemService()!! if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent) diff --git a/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt b/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt index a9375b6545..f34260c941 100644 --- a/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt +++ b/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt @@ -147,8 +147,11 @@ fun openFileSelection(activity: Activity, * Send an email to address with optional subject and message */ fun sendMailTo(address: String, subject: String? = null, message: String? = null, activity: Activity) { - val intent = Intent(Intent.ACTION_SENDTO, Uri.fromParts( - "mailto", address, null)) + val intent = Intent( + Intent.ACTION_SENDTO, Uri.fromParts( + "mailto", address, null + ) + ) intent.putExtra(Intent.EXTRA_SUBJECT, subject) intent.putExtra(Intent.EXTRA_TEXT, message) @@ -248,7 +251,12 @@ private fun appendTimeToFilename(name: String): String { return """${filename}_$dateExtension.$fileExtension""" } -suspend fun saveMedia(context: Context, file: File, title: String, mediaMimeType: String?, notificationUtils: NotificationUtils) { +suspend fun saveMedia(context: Context, + file: File, + title: String, + mediaMimeType: String?, + notificationUtils: NotificationUtils, + now: Long) { withContext(Dispatchers.IO) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val filename = appendTimeToFilename(title) @@ -257,8 +265,8 @@ suspend fun saveMedia(context: Context, file: File, title: String, mediaMimeType put(MediaStore.Images.Media.TITLE, filename) put(MediaStore.Images.Media.DISPLAY_NAME, filename) put(MediaStore.Images.Media.MIME_TYPE, mediaMimeType) - put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis()) - put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis()) + put(MediaStore.Images.Media.DATE_ADDED, now) + put(MediaStore.Images.Media.DATE_TAKEN, now) } val externalContentUri = when { mediaMimeType?.isMimeTypeImage() == true -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI @@ -289,7 +297,7 @@ suspend fun saveMedia(context: Context, file: File, title: String, mediaMimeType } } } else { - saveMediaLegacy(context, mediaMimeType, title, file) + saveMediaLegacy(context, mediaMimeType, title, file, now) } } } @@ -298,7 +306,8 @@ suspend fun saveMedia(context: Context, file: File, title: String, mediaMimeType private fun saveMediaLegacy(context: Context, mediaMimeType: String?, title: String, - file: File) { + file: File, + now: Long) { val state = Environment.getExternalStorageState() if (Environment.MEDIA_MOUNTED != state) { context.toast(context.getString(R.string.error_saving_media_file)) @@ -319,7 +328,7 @@ private fun saveMediaLegacy(context: Context, } else { title } - val savedFile = saveFileIntoLegacy(file, downloadDir, outputFilename) + val savedFile = saveFileIntoLegacy(file, downloadDir, outputFilename, now) if (savedFile != null) { val downloadManager = context.getSystemService() downloadManager?.addCompletedDownload( @@ -329,7 +338,8 @@ private fun saveMediaLegacy(context: Context, mediaMimeType ?: MimeTypes.OctetStream, savedFile.absolutePath, savedFile.length(), - true) + true + ) addToGallery(savedFile, mediaMimeType, context) } } catch (error: Throwable) { @@ -411,7 +421,7 @@ fun selectTxtFileToWrite( * @return the created file */ @Suppress("DEPRECATION") -fun saveFileIntoLegacy(sourceFile: File, dstDirPath: File, outputFilename: String?): File? { +fun saveFileIntoLegacy(sourceFile: File, dstDirPath: File, outputFilename: String?, now: Long): File? { // defines another name for the external media var dstFileName: String @@ -423,7 +433,7 @@ fun saveFileIntoLegacy(sourceFile: File, dstDirPath: File, outputFilename: Strin if (dotPos > 0) { fileExt = sourceFile.name.substring(dotPos) } - dstFileName = "vector_" + System.currentTimeMillis() + fileExt + dstFileName = "vector_$now$fileExt" } else { dstFileName = outputFilename } diff --git a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt index 5b9c3f7fb4..729ac10d4b 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt @@ -45,6 +45,7 @@ import im.vector.app.core.extensions.insertBeforeLast import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider +import im.vector.app.core.time.Clock import im.vector.app.core.utils.OnSnapPositionChangeListener import im.vector.app.core.utils.SnapOnScrollListener import im.vector.app.core.utils.attachSnapHelperWithListener @@ -64,7 +65,8 @@ data class AttachmentsPreviewArgs( class AttachmentsPreviewFragment @Inject constructor( private val attachmentMiniaturePreviewController: AttachmentMiniaturePreviewController, private val attachmentBigPreviewController: AttachmentBigPreviewController, - private val colorProvider: ColorProvider + private val colorProvider: ColorProvider, + private val clock: Clock, ) : VectorBaseFragment(), AttachmentMiniaturePreviewController.Callback { private val fragmentArgs: AttachmentsPreviewArgs by args() @@ -192,7 +194,7 @@ class AttachmentsPreviewFragment @Inject constructor( private fun handleEditAction() = withState(viewModel) { val currentAttachment = it.attachments.getOrNull(it.currentAttachmentIndex) ?: return@withState - val destinationFile = File(requireContext().cacheDir, currentAttachment.name.insertBeforeLast("_edited_image_${System.currentTimeMillis()}")) + val destinationFile = File(requireContext().cacheDir, currentAttachment.name.insertBeforeLast("_edited_image_${clock.epochMillis()}")) val uri = currentAttachment.queryUri createUCropWithDefaultSettings(colorProvider, uri, destinationFile.toUri(), currentAttachment.name) .getIntent(requireContext()) diff --git a/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt b/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt index 07062fc732..b0da4f0e18 100644 --- a/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt +++ b/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt @@ -19,6 +19,7 @@ package im.vector.app.features.call.conference import im.vector.app.R import im.vector.app.core.network.await import im.vector.app.core.resources.StringProvider +import im.vector.app.core.time.Clock import im.vector.app.core.utils.ensureProtocol import im.vector.app.core.utils.toBase32String import im.vector.app.features.call.conference.jwt.JitsiJWTFactory @@ -46,7 +47,9 @@ class JitsiService @Inject constructor( private val rawService: RawService, private val stringProvider: StringProvider, private val themeProvider: ThemeProvider, - private val jitsiJWTFactory: JitsiJWTFactory) { + private val jitsiJWTFactory: JitsiJWTFactory, + private val clock: Clock, +) { companion object { const val JITSI_OPEN_ID_TOKEN_JWT_AUTH = "openidtoken-jwt" @@ -60,7 +63,7 @@ class JitsiService @Inject constructor( suspend fun createJitsiWidget(roomId: String, withVideo: Boolean): Widget { // Build data for a jitsi widget - val widgetId: String = WidgetType.Jitsi.preferred + "_" + session.myUserId + "_" + System.currentTimeMillis() + val widgetId: String = WidgetType.Jitsi.preferred + "_" + session.myUserId + "_" + clock.epochMillis() val preferredJitsiDomain = tryOrNull { rawService.getElementWellknown(session.sessionParams) ?.jitsiServer diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/ScreenCaptureService.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/ScreenCaptureService.kt index f1a4975751..489b2d1eae 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/ScreenCaptureService.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/ScreenCaptureService.kt @@ -21,6 +21,7 @@ import android.os.Binder import android.os.IBinder import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.services.VectorService +import im.vector.app.core.time.Clock import im.vector.app.features.notifications.NotificationUtils import javax.inject.Inject @@ -28,6 +29,7 @@ import javax.inject.Inject class ScreenCaptureService : VectorService() { @Inject lateinit var notificationUtils: NotificationUtils + @Inject lateinit var clock: Clock private val binder = LocalBinder() override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { @@ -37,7 +39,7 @@ class ScreenCaptureService : VectorService() { } private fun showStickyNotification() { - val notificationId = System.currentTimeMillis().toInt() + val notificationId = clock.epochMillis().toInt() val notification = notificationUtils.buildScreenSharingNotification() startForeground(notificationId, notification) } diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt index 34aa7ba0ee..dfa7d1aaa3 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupSharedViewModel.kt @@ -22,6 +22,7 @@ import androidx.lifecycle.ViewModel import com.nulabinc.zxcvbn.Strength import im.vector.app.R import im.vector.app.core.platform.WaitingViewData +import im.vector.app.core.time.Clock import im.vector.app.core.utils.LiveEvent import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.listeners.ProgressListener @@ -37,7 +38,9 @@ import javax.inject.Inject /** * The shared view model between all fragments. */ -class KeysBackupSetupSharedViewModel @Inject constructor() : ViewModel() { +class KeysBackupSetupSharedViewModel @Inject constructor( + private val clock: Clock, +) : ViewModel() { companion object { const val NAVIGATE_TO_STEP_2 = "NAVIGATE_TO_STEP_2" @@ -85,7 +88,7 @@ class KeysBackupSetupSharedViewModel @Inject constructor() : ViewModel() { fun prepareRecoveryKey(context: Context, withPassphrase: String?) { // Update requestId - currentRequestId.value = System.currentTimeMillis() + currentRequestId.value = clock.epochMillis() isCreatingBackupVersion.value = true recoveryKey.value = null @@ -101,9 +104,11 @@ class KeysBackupSetupSharedViewModel @Inject constructor() : ViewModel() { return } - loadingStatus.value = WaitingViewData(context.getString(R.string.keys_backup_setup_step3_generating_key_status), + loadingStatus.value = WaitingViewData( + context.getString(R.string.keys_backup_setup_step3_generating_key_status), progress, - total) + total + ) } }, object : MatrixCallback { diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/IncomingVerificationRequestHandler.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/IncomingVerificationRequestHandler.kt index 2e9fe1bcf9..e8f0bd344f 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/IncomingVerificationRequestHandler.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/IncomingVerificationRequestHandler.kt @@ -18,6 +18,7 @@ package im.vector.app.features.crypto.verification import android.content.Context import im.vector.app.R import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.core.time.Clock import im.vector.app.features.displayname.getBestName import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.RoomDetailActivity @@ -42,7 +43,9 @@ import javax.inject.Singleton class IncomingVerificationRequestHandler @Inject constructor( private val context: Context, private var avatarRenderer: Provider, - private val popupAlertManager: PopupAlertManager) : VerificationService.Listener { + private val popupAlertManager: PopupAlertManager, + private val clock: Clock, +) : VerificationService.Listener { private var session: Session? = null @@ -104,7 +107,7 @@ class IncomingVerificationRequestHandler @Inject constructor( } ) // 10mn expiration - expirationTimestamp = System.currentTimeMillis() + (10 * 60 * 1000L) + expirationTimestamp = clock.epochMillis() + (10 * 60 * 1000L) } popupAlertManager.postVectorAlert(alert) } @@ -168,7 +171,7 @@ class IncomingVerificationRequestHandler @Inject constructor( } colorAttribute = R.attr.vctr_notice_secondary // 5mn expiration - expirationTimestamp = System.currentTimeMillis() + (5 * 60 * 1000L) + expirationTimestamp = clock.epochMillis() + (5 * 60 * 1000L) } popupAlertManager.postVectorAlert(alert) } diff --git a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt index 3ca19b39f9..34bdc5fcd3 100644 --- a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt @@ -29,6 +29,7 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModelAction +import im.vector.app.core.time.Clock import im.vector.app.features.settings.VectorPreferences import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged @@ -56,10 +57,12 @@ data class DeviceDetectionInfo( val currentSessionTrust: Boolean ) -class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted initialState: UnknownDevicesState, - session: Session, - private val vectorPreferences: VectorPreferences) : - VectorViewModel(initialState) { +class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor( + @Assisted initialState: UnknownDevicesState, + session: Session, + private val vectorPreferences: VectorPreferences, + clock: Clock, +) : VectorViewModel(initialState) { sealed class Action : VectorViewModelAction { data class IgnoreDevice(val deviceIds: List) : Action() @@ -75,11 +78,10 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted private val ignoredDeviceList = ArrayList() init { - val currentSessionTs = session.cryptoService().getCryptoDeviceInfo(session.myUserId) .firstOrNull { it.deviceId == session.sessionParams.deviceId } ?.firstTimeSeenLocalTs - ?: System.currentTimeMillis() + ?: clock.epochMillis() Timber.v("## Detector - Current Session first time seen $currentSessionTs") ignoredDeviceList.addAll( diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/ChatEffectManager.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/ChatEffectManager.kt index f95baae36b..fa19e39ae7 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/ChatEffectManager.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/ChatEffectManager.kt @@ -16,6 +16,7 @@ package im.vector.app.features.home.room.detail +import im.vector.app.core.time.Clock import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessageType @@ -45,7 +46,9 @@ fun ChatEffect.toMessageType(): String { * precisely an event decrypted with a few delay won't trigger an effect; it's acceptable) * Events that are more that 10s old won't trigger effects */ -class ChatEffectManager @Inject constructor() { +class ChatEffectManager @Inject constructor( + private val clock: Clock, +) { interface Delegate { fun stopEffects() @@ -61,7 +64,7 @@ class ChatEffectManager @Inject constructor() { fun checkForEffect(event: TimelineEvent) { val age = event.root.ageLocalTs ?: 0 - val now = System.currentTimeMillis() + val now = clock.epochMillis() // messages older than 10s should not trigger any effect if ((now - age) >= 10_000) return val content = event.root.getClearContent()?.toModel() ?: return diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomMessageTouchHelperCallback.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomMessageTouchHelperCallback.kt index 9f10805f95..1f1124b8c0 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomMessageTouchHelperCallback.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomMessageTouchHelperCallback.kt @@ -33,14 +33,18 @@ import com.airbnb.epoxy.EpoxyModel import com.airbnb.epoxy.EpoxyTouchHelperCallback import com.airbnb.epoxy.EpoxyViewHolder import im.vector.app.R +import im.vector.app.core.time.Clock import im.vector.app.features.themes.ThemeUtils import timber.log.Timber import kotlin.math.abs import kotlin.math.min -class RoomMessageTouchHelperCallback(private val context: Context, - @DrawableRes actionIcon: Int, - private val handler: QuickReplayHandler) : EpoxyTouchHelperCallback() { +class RoomMessageTouchHelperCallback( + private val context: Context, + @DrawableRes actionIcon: Int, + private val handler: QuickReplayHandler, + private val clock: Clock, +) : EpoxyTouchHelperCallback() { interface QuickReplayHandler { fun performQuickReplyOnHolder(model: EpoxyModel<*>) @@ -141,7 +145,7 @@ class RoomMessageTouchHelperCallback(private val context: Context, private fun drawReplyButton(canvas: Canvas, itemView: View) { // Timber.v("drawReplyButton") val translationX = abs(itemView.translationX) - val newTime = System.currentTimeMillis() + val newTime = clock.epochMillis() val dt = min(17, newTime - lastReplyButtonAnimationTime) lastReplyButtonAnimationTime = newTime val showing = translationX >= minShowDistance diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt index 4603793bd5..60a1ddcc62 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt @@ -296,7 +296,7 @@ class TimelineFragment @Inject constructor( private const val ircPattern = " (IRC)" } - private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider) + private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock) private val timelineArgs: TimelineArgs by args() private val glideRequests by lazy { @@ -1443,7 +1443,7 @@ class TimelineFragment @Inject constructor( } } } - val swipeCallback = RoomMessageTouchHelperCallback(requireContext(), R.drawable.ic_reply, quickReplyHandler) + val swipeCallback = RoomMessageTouchHelperCallback(requireContext(), R.drawable.ic_reply, quickReplyHandler, clock) val touchHelper = ItemTouchHelper(swipeCallback) touchHelper.attachToRecyclerView(views.timelineRecyclerView) } @@ -2186,7 +2186,8 @@ class TimelineFragment @Inject constructor( file = it, title = action.messageContent.body, mediaMimeType = action.messageContent.mimeType ?: getMimeTypeFromUri(requireContext(), it.toUri()), - notificationUtils = notificationUtils + notificationUtils = notificationUtils, + now = clock.epochMillis() ) } .onFailure { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewState.kt index 95553eb1cd..10263c1abc 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewState.kt @@ -21,6 +21,7 @@ import im.vector.app.features.home.room.detail.arguments.TimelineArgs import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import kotlin.random.Random /** * Describes the current send mode: @@ -35,7 +36,7 @@ sealed interface SendMode { val text: String, val fromSharing: Boolean, // This is necessary for forcing refresh on selectSubscribe - private val ts: Long = System.currentTimeMillis() + private val ts: Int = Random.nextInt() ) : SendMode data class Quote(val timelineEvent: TimelineEvent, val text: String) : SendMode @@ -83,7 +84,8 @@ data class MessageComposerViewState( constructor(args: TimelineArgs) : this( roomId = args.roomId, startsThread = args.threadTimelineArgs?.startsThread.orFalse(), - rootThreadEventId = args.threadTimelineArgs?.rootThreadEventId) + rootThreadEventId = args.threadTimelineArgs?.rootThreadEventId + ) fun isInThreadTimeline(): Boolean = rootThreadEventId != null } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt index 4f951dfecb..c77cdceed0 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt @@ -30,6 +30,7 @@ import im.vector.app.core.epoxy.loadingItem import im.vector.app.core.epoxy.noResultItem import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.UserPreferencesProvider +import im.vector.app.core.time.Clock import im.vector.app.core.ui.list.GenericHeaderItem_ import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.timeline.format.DisplayableEventFormatter @@ -47,7 +48,8 @@ class SearchResultController @Inject constructor( private val stringProvider: StringProvider, private val dateFormatter: VectorDateFormatter, private val displayableEventFormatter: DisplayableEventFormatter, - private val userPreferencesProvider: UserPreferencesProvider + private val userPreferencesProvider: UserPreferencesProvider, + private val clock: Clock, ) : TypedEpoxyController() { var listener: Listener? = null @@ -109,7 +111,7 @@ class SearchResultController @Inject constructor( val spannable = setHighLightedText(text, data.highlights) ?: return@forEach val eventDate = Calendar.getInstance().apply { - timeInMillis = eventAndSender.event.originServerTs ?: System.currentTimeMillis() + timeInMillis = eventAndSender.event.originServerTs ?: clock.epochMillis() } if (lastDate?.get(Calendar.DAY_OF_YEAR) != eventDate.get(Calendar.DAY_OF_YEAR)) { GenericHeaderItem_() @@ -125,7 +127,8 @@ class SearchResultController @Inject constructor( .formattedDate(dateFormatter.format(event.originServerTs, DateFormatKind.MESSAGE_SIMPLE)) .spannable(spannable.toEpoxyCharSequence()) .sender(eventAndSender.sender - ?: eventAndSender.event.senderId?.let { session.roomService().getRoomMember(it, data.roomId) }?.toMatrixItem()) + ?: eventAndSender.event.senderId?.let { session.roomService().getRoomMember(it, data.roomId) }?.toMatrixItem() + ) .threadDetails(event.threadDetails) .threadSummaryFormatted(displayableEventFormatter.formatThreadSummary(event.threadDetails?.threadSummaryLatestEvent).toString()) .areThreadMessagesEnabled(userPreferencesProvider.areThreadMessagesEnabled()) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt index 8cea57399a..6c9f7ac4ff 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt @@ -31,6 +31,7 @@ import im.vector.app.core.epoxy.LoadingItem_ import im.vector.app.core.extensions.localDateTime import im.vector.app.core.extensions.nextOrNull import im.vector.app.core.extensions.prevOrNull +import im.vector.app.core.time.Clock import im.vector.app.features.home.room.detail.JitsiState import im.vector.app.features.home.room.detail.RoomDetailAction import im.vector.app.features.home.room.detail.RoomDetailViewState @@ -78,19 +79,21 @@ import javax.inject.Inject import kotlin.math.min import kotlin.system.measureTimeMillis -class TimelineEventController @Inject constructor(private val dateFormatter: VectorDateFormatter, - private val vectorPreferences: VectorPreferences, - private val contentUploadStateTrackerBinder: ContentUploadStateTrackerBinder, - private val contentDownloadStateTrackerBinder: ContentDownloadStateTrackerBinder, - private val timelineItemFactory: TimelineItemFactory, - private val timelineMediaSizeProvider: TimelineMediaSizeProvider, - private val mergedHeaderItemFactory: MergedHeaderItemFactory, - private val session: Session, - @TimelineEventControllerHandler - private val backgroundHandler: Handler, - private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper, - private val readReceiptsItemFactory: ReadReceiptsItemFactory, - private val reactionListFactory: ReactionsSummaryFactory +class TimelineEventController @Inject constructor( + private val dateFormatter: VectorDateFormatter, + private val vectorPreferences: VectorPreferences, + private val contentUploadStateTrackerBinder: ContentUploadStateTrackerBinder, + private val contentDownloadStateTrackerBinder: ContentDownloadStateTrackerBinder, + private val timelineItemFactory: TimelineItemFactory, + private val timelineMediaSizeProvider: TimelineMediaSizeProvider, + private val mergedHeaderItemFactory: MergedHeaderItemFactory, + private val session: Session, + @TimelineEventControllerHandler + private val backgroundHandler: Handler, + private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper, + private val readReceiptsItemFactory: ReadReceiptsItemFactory, + private val reactionListFactory: ReactionsSummaryFactory, + private val clock: Clock, ) : EpoxyController(backgroundHandler, backgroundHandler), Timeline.Listener, EpoxyController.Interceptor { /** @@ -209,8 +212,10 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec override fun onChanged(position: Int, count: Int, payload: Any?) { synchronized(modelCache) { assertUpdateCallbacksAllowed() - Timber.v("listUpdateCallback.onChanged(position: $position, count: $count). " + - "\ncurrentSnapshot has size of ${currentSnapshot.size} items") + Timber.v( + "listUpdateCallback.onChanged(position: $position, count: $count). " + + "\ncurrentSnapshot has size of ${currentSnapshot.size} items" + ) (position until position + count).forEach { // Invalidate cache modelCache[it] = null @@ -238,8 +243,10 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec override fun onMoved(fromPosition: Int, toPosition: Int) { synchronized(modelCache) { assertUpdateCallbacksAllowed() - Timber.v("listUpdateCallback.onMoved(fromPosition: $fromPosition, toPosition: $toPosition). " + - "\ncurrentSnapshot has size of ${currentSnapshot.size} items") + Timber.v( + "listUpdateCallback.onMoved(fromPosition: $fromPosition, toPosition: $toPosition). " + + "\ncurrentSnapshot has size of ${currentSnapshot.size} items" + ) val model = modelCache.removeAt(fromPosition) modelCache.add(toPosition, model) requestModelBuild() @@ -249,8 +256,10 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec override fun onInserted(position: Int, count: Int) { synchronized(modelCache) { assertUpdateCallbacksAllowed() - Timber.v("listUpdateCallback.onInserted(position: $position, count: $count). " + - "\ncurrentSnapshot has size of ${currentSnapshot.size} items") + Timber.v( + "listUpdateCallback.onInserted(position: $position, count: $count). " + + "\ncurrentSnapshot has size of ${currentSnapshot.size} items" + ) repeat(count) { modelCache.add(position, null) } @@ -261,8 +270,10 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec override fun onRemoved(position: Int, count: Int) { synchronized(modelCache) { assertUpdateCallbacksAllowed() - Timber.v("listUpdateCallback.onRemoved(position: $position, count: $count). " + - "\ncurrentSnapshot has size of ${currentSnapshot.size} items") + Timber.v( + "listUpdateCallback.onRemoved(position: $position, count: $count). " + + "\ncurrentSnapshot has size of ${currentSnapshot.size} items" + ) repeat(count) { modelCache.removeAt(position) } @@ -314,7 +325,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec if (partialState.roomSummary?.membership != Membership.JOIN) { return } - val timestamp = System.currentTimeMillis() + val timestamp = clock.epochMillis() val showingForwardLoader = LoadingItem_() .id("forward_loading_item_$timestamp") @@ -406,14 +417,16 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec timelineEvent = it, highlightedEventId = partialState.highlightedEventId, isFromThreadTimeline = partialState.isFromThreadTimeline(), - rootThreadEventId = partialState.rootThreadEventId) + rootThreadEventId = partialState.rootThreadEventId + ) } val nextDisplayableEvent = currentSnapshot.subList(position + 1, currentSnapshot.size).firstOrNull { timelineEventVisibilityHelper.shouldShowEvent( timelineEvent = it, highlightedEventId = partialState.highlightedEventId, isFromThreadTimeline = partialState.isFromThreadTimeline(), - rootThreadEventId = partialState.rootThreadEventId) + rootThreadEventId = partialState.rootThreadEventId + ) } val timelineEventsGroup = timelineEventsGroups.getOrNull(event) val params = TimelineItemFactoryParams( @@ -466,7 +479,8 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec position: Int, receiptsByEvents: Map>): CacheItemData { val wantsDateSeparator = wantsDateSeparator(event, nextEvent) - val mergedHeaderModel = mergedHeaderItemFactory.create(event, + val mergedHeaderModel = mergedHeaderItemFactory.create( + event, nextEvent = nextEvent, partialState = partialState, items = this@TimelineEventController.currentSnapshot, @@ -537,7 +551,8 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec timelineEvent = event, highlightedEventId = partialState.highlightedEventId, isFromThreadTimeline = partialState.isFromThreadTimeline(), - rootThreadEventId = partialState.rootThreadEventId)) { + rootThreadEventId = partialState.rootThreadEventId + )) { lastShownEventId = event.eventId } if (lastShownEventId == null) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt index 63a34fe713..f96ee7eee2 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryEpoxyController.kt @@ -26,6 +26,7 @@ import im.vector.app.core.date.DateFormatKind import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.StringProvider +import im.vector.app.core.time.Clock import im.vector.app.core.ui.list.genericFooterItem import im.vector.app.core.ui.list.genericHeaderItem import im.vector.app.core.ui.list.genericItem @@ -49,7 +50,8 @@ class ViewEditHistoryEpoxyController @Inject constructor( private val stringProvider: StringProvider, private val colorProvider: ColorProvider, private val eventHtmlRenderer: EventHtmlRenderer, - private val dateFormatter: VectorDateFormatter + private val dateFormatter: VectorDateFormatter, + private val clock: Clock, ) : TypedEpoxyController() { override fun buildModels(state: ViewEditHistoryViewState) { @@ -86,7 +88,7 @@ class ViewEditHistoryEpoxyController @Inject constructor( val evDate = Calendar.getInstance().apply { timeInMillis = timelineEvent.originServerTs - ?: System.currentTimeMillis() + ?: clock.epochMillis() } if (lastDate?.get(Calendar.DAY_OF_YEAR) != evDate.get(Calendar.DAY_OF_YEAR)) { // need to display header with day diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineControllerInterceptorHelper.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineControllerInterceptorHelper.kt index 8a0e1e18fd..e9361e564c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineControllerInterceptorHelper.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineControllerInterceptorHelper.kt @@ -25,6 +25,7 @@ import im.vector.app.features.home.room.detail.timeline.item.DaySeparatorItem import im.vector.app.features.home.room.detail.timeline.item.ItemWithEvents import im.vector.app.features.home.room.detail.timeline.item.TimelineReadMarkerItem_ import org.matrix.android.sdk.api.session.room.timeline.Timeline +import kotlin.random.Random import kotlin.reflect.KMutableProperty0 private const val DEFAULT_PREFETCH_THRESHOLD = 30 @@ -104,7 +105,7 @@ class TimelineControllerInterceptorHelper(private val positionOfReadMarker: KMut .coerceAtLeast(0) val loadingItem = LoadingItem_() - .id("prefetch_backward_loading${System.currentTimeMillis()}") + .id("prefetch_backward_loading${Random.nextLong()}") .showLoader(false) .setVisibilityStateChangedListener(Timeline.Direction.BACKWARDS, callback) @@ -120,7 +121,7 @@ class TimelineControllerInterceptorHelper(private val positionOfReadMarker: KMut .coerceAtLeast(0) val loadingItem = LoadingItem_() - .id("prefetch_forward_loading${System.currentTimeMillis()}") + .id("prefetch_forward_loading${Random.nextLong()}") .showLoader(false) .setVisibilityStateChangedListener(Timeline.Direction.FORWARDS, callback) add(indexOfPrefetchForward, loadingItem) diff --git a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedFragment.kt b/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedFragment.kt index 8223053ad8..b0caf80d82 100644 --- a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedFragment.kt @@ -31,6 +31,7 @@ import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper import im.vector.app.core.intent.getFilenameFromUri import im.vector.app.core.resources.ColorProvider +import im.vector.app.core.time.Clock import im.vector.app.databinding.DialogBaseEditTextBinding import im.vector.app.databinding.FragmentLoginAccountCreatedBinding import im.vector.app.features.displayname.getBestName @@ -52,13 +53,14 @@ class AccountCreatedFragment @Inject constructor( private val avatarRenderer: AvatarRenderer, private val dateFormatter: VectorDateFormatter, private val matrixItemColorProvider: MatrixItemColorProvider, + private val clock: Clock, colorProvider: ColorProvider ) : AbstractLoginFragment2(), GalleryOrCameraDialogHelper.Listener { private val viewModel: AccountCreatedViewModel by fragmentViewModel() - private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider) + private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock) override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginAccountCreatedBinding { return FragmentLoginAccountCreatedBinding.inflate(inflater, container, false) @@ -73,7 +75,7 @@ class AccountCreatedFragment @Inject constructor( viewModel.onEach { invalidateState(it) } - views.loginAccountCreatedTime.text = dateFormatter.format(System.currentTimeMillis(), DateFormatKind.MESSAGE_SIMPLE) + views.loginAccountCreatedTime.text = dateFormatter.format(clock.epochMillis(), DateFormatKind.MESSAGE_SIMPLE) } private fun observeViewEvents() { diff --git a/vector/src/main/java/im/vector/app/features/media/domain/usecase/DownloadMediaUseCase.kt b/vector/src/main/java/im/vector/app/features/media/domain/usecase/DownloadMediaUseCase.kt index b0401ccd30..32b804e43b 100644 --- a/vector/src/main/java/im/vector/app/features/media/domain/usecase/DownloadMediaUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/media/domain/usecase/DownloadMediaUseCase.kt @@ -20,6 +20,7 @@ import android.content.Context import androidx.core.net.toUri import dagger.hilt.android.qualifiers.ApplicationContext import im.vector.app.core.intent.getMimeTypeFromUri +import im.vector.app.core.time.Clock import im.vector.app.core.utils.saveMedia import im.vector.app.features.notifications.NotificationUtils import kotlinx.coroutines.withContext @@ -30,7 +31,8 @@ import javax.inject.Inject class DownloadMediaUseCase @Inject constructor( @ApplicationContext private val appContext: Context, private val session: Session, - private val notificationUtils: NotificationUtils + private val notificationUtils: NotificationUtils, + private val clock: Clock, ) { suspend fun execute(input: File): Result = withContext(session.coroutineDispatchers.io) { @@ -40,7 +42,8 @@ class DownloadMediaUseCase @Inject constructor( file = input, title = input.name, mediaMimeType = getMimeTypeFromUri(appContext, input.toUri()), - notificationUtils = notificationUtils + notificationUtils = notificationUtils, + now = clock.epochMillis() ) } } diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt index 43eab0c1f2..4ac7461f5a 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt @@ -20,6 +20,7 @@ import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.extensions.takeAs import im.vector.app.core.resources.StringProvider +import im.vector.app.core.time.Clock import im.vector.app.features.displayname.getBestName import im.vector.app.features.home.room.detail.timeline.format.DisplayableEventFormatter import im.vector.app.features.home.room.detail.timeline.format.NoticeEventFormatter @@ -58,7 +59,8 @@ import javax.inject.Inject class NotifiableEventResolver @Inject constructor( private val stringProvider: StringProvider, private val noticeEventFormatter: NoticeEventFormatter, - private val displayableEventFormatter: DisplayableEventFormatter + private val displayableEventFormatter: DisplayableEventFormatter, + private val clock: Clock, ) { // private val eventDisplay = RiotEventDisplay(context) @@ -86,7 +88,7 @@ class NotifiableEventResolver @Inject constructor( eventId = event.eventId!!, editedEventId = timelineEvent.getEditedEventId(), noisy = false, // will be updated - timestamp = event.originServerTs ?: System.currentTimeMillis(), + timestamp = event.originServerTs ?: clock.epochMillis(), description = bodyPreview, title = stringProvider.getString(R.string.notification_unknown_new_event), soundName = null, @@ -178,15 +180,19 @@ class NotifiableEventResolver @Inject constructor( roomName = roomName, roomIsDirect = room.roomSummary()?.isDirect ?: false, roomAvatarPath = session.contentUrlResolver() - .resolveThumbnail(room.roomSummary()?.avatarUrl, + .resolveThumbnail( + room.roomSummary()?.avatarUrl, 250, 250, - ContentUrlResolver.ThumbnailMethod.SCALE), + ContentUrlResolver.ThumbnailMethod.SCALE + ), senderAvatarPath = session.contentUrlResolver() - .resolveThumbnail(event.senderInfo.avatarUrl, + .resolveThumbnail( + event.senderInfo.avatarUrl, 250, 250, - ContentUrlResolver.ThumbnailMethod.SCALE), + ContentUrlResolver.ThumbnailMethod.SCALE + ), matrixID = session.myUserId, soundName = null ) diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationBroadcastReceiver.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationBroadcastReceiver.kt index 3d5bd7930c..261fcdd2ce 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationBroadcastReceiver.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationBroadcastReceiver.kt @@ -23,6 +23,7 @@ import androidx.core.app.RemoteInput import dagger.hilt.android.AndroidEntryPoint import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.time.Clock import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom import im.vector.app.features.session.coroutineScope @@ -45,6 +46,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() { @Inject lateinit var notificationDrawerManager: NotificationDrawerManager @Inject lateinit var activeSessionHolder: ActiveSessionHolder @Inject lateinit var analyticsTracker: AnalyticsTracker + @Inject lateinit var clock: Clock override fun onReceive(context: Context?, intent: Intent?) { if (intent == null || context == null) return @@ -137,7 +139,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() { eventId = UUID.randomUUID().toString(), editedEventId = null, noisy = false, - timestamp = System.currentTimeMillis(), + timestamp = clock.epochMillis(), senderName = session.roomService().getRoomMember(session.myUserId, room.roomId)?.displayName ?: context?.getString(R.string.notification_sender_me), senderId = session.myUserId, @@ -188,7 +190,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() { val notifiableMessageEvent = NotifiableMessageEvent( event.eventId, false, - System.currentTimeMillis(), + clock.epochMillis(), session.myUser?.displayname ?: context?.getString(R.string.notification_sender_me), session.myUserId, diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index e44f42d5cd..08f6ccc2f3 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -51,6 +51,7 @@ import im.vector.app.core.extensions.createIgnoredUri import im.vector.app.core.platform.PendingIntentCompat import im.vector.app.core.resources.StringProvider import im.vector.app.core.services.CallService +import im.vector.app.core.time.Clock import im.vector.app.core.utils.startNotificationChannelSettingsIntent import im.vector.app.features.call.VectorCallActivity import im.vector.app.features.call.service.CallHeadsUpActionReceiver @@ -72,9 +73,12 @@ import kotlin.random.Random * Note: Cannot inject ColorProvider in the constructor, because it requires an Activity */ @Singleton -class NotificationUtils @Inject constructor(private val context: Context, - private val stringProvider: StringProvider, - private val vectorPreferences: VectorPreferences) { +class NotificationUtils @Inject constructor( + private val context: Context, + private val stringProvider: StringProvider, + private val vectorPreferences: VectorPreferences, + private val clock: Clock, +) { companion object { /* ========================================================================================== @@ -323,7 +327,7 @@ class NotificationUtils @Inject constructor(private val context: Context, } val contentPendingIntent = PendingIntent.getActivity( context, - System.currentTimeMillis().toInt(), + clock.epochMillis().toInt(), contentIntent, PendingIntentCompat.FLAG_IMMUTABLE ) @@ -337,7 +341,7 @@ class NotificationUtils @Inject constructor(private val context: Context, mode = VectorCallActivity.INCOMING_ACCEPT ) ) - .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE) + .getPendingIntent(clock.epochMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE) val rejectCallPendingIntent = buildRejectCallPendingIntent(call.callId) @@ -392,7 +396,7 @@ class NotificationUtils @Inject constructor(private val context: Context, } val contentPendingIntent = PendingIntent.getActivity( context, - System.currentTimeMillis().toInt(), + clock.epochMillis().toInt(), contentIntent, PendingIntentCompat.FLAG_IMMUTABLE ) @@ -453,7 +457,7 @@ class NotificationUtils @Inject constructor(private val context: Context, val contentPendingIntent = TaskStackBuilder.create(context) .addNextIntentWithParentStack(HomeActivity.newIntent(context)) .addNextIntent(VectorCallActivity.newIntent(context, call, null)) - .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE) + .getPendingIntent(clock.epochMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE) builder.setContentIntent(contentPendingIntent) @@ -467,7 +471,7 @@ class NotificationUtils @Inject constructor(private val context: Context, } return PendingIntent.getBroadcast( context, - System.currentTimeMillis().toInt(), + clock.epochMillis().toInt(), rejectCallActionReceiver, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE ) @@ -515,7 +519,7 @@ class NotificationUtils @Inject constructor(private val context: Context, val contentPendingIntent = TaskStackBuilder.create(context) .addNextIntentWithParentStack(HomeActivity.newIntent(context)) .addNextIntent(RoomDetailActivity.newIntent(context, TimelineArgs(callInformation.nativeRoomId))) - .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE) + .getPendingIntent(clock.epochMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE) builder.setContentIntent(contentPendingIntent) return builder.build() @@ -562,7 +566,7 @@ class NotificationUtils @Inject constructor(private val context: Context, } PendingIntent.getActivity( context, - System.currentTimeMillis().toInt(), + clock.epochMillis().toInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE ).let { @@ -636,7 +640,7 @@ class NotificationUtils @Inject constructor(private val context: Context, markRoomReadIntent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomInfo.roomId) val markRoomReadPendingIntent = PendingIntent.getBroadcast( context, - System.currentTimeMillis().toInt(), + clock.epochMillis().toInt(), markRoomReadIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE ) @@ -677,7 +681,7 @@ class NotificationUtils @Inject constructor(private val context: Context, intent.action = DISMISS_ROOM_NOTIF_ACTION val pendingIntent = PendingIntent.getBroadcast( context.applicationContext, - System.currentTimeMillis().toInt(), + clock.epochMillis().toInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE ) @@ -712,7 +716,7 @@ class NotificationUtils @Inject constructor(private val context: Context, rejectIntent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomId) val rejectIntentPendingIntent = PendingIntent.getBroadcast( context, - System.currentTimeMillis().toInt(), + clock.epochMillis().toInt(), rejectIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE ) @@ -730,7 +734,7 @@ class NotificationUtils @Inject constructor(private val context: Context, joinIntent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomId) val joinIntentPendingIntent = PendingIntent.getBroadcast( context, - System.currentTimeMillis().toInt(), + clock.epochMillis().toInt(), joinIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE ) @@ -811,7 +815,7 @@ class NotificationUtils @Inject constructor(private val context: Context, .addNextIntentWithParentStack(HomeActivity.newIntent(context)) .addNextIntent(roomIntentTap) .getPendingIntent( - System.currentTimeMillis().toInt(), + clock.epochMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE ) } @@ -844,7 +848,7 @@ class NotificationUtils @Inject constructor(private val context: Context, intent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomId) return PendingIntent.getBroadcast( context, - System.currentTimeMillis().toInt(), + clock.epochMillis().toInt(), intent, // PendingIntents attached to actions with remote inputs must be mutable PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_MUTABLE diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthChooseProfilePictureFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthChooseProfilePictureFragment.kt index 81300932db..0ccff7dffc 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthChooseProfilePictureFragment.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthChooseProfilePictureFragment.kt @@ -29,6 +29,7 @@ import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper import im.vector.app.core.extensions.singletonEntryPoint import im.vector.app.core.resources.ColorProvider +import im.vector.app.core.time.Clock import im.vector.app.databinding.FragmentFtueProfilePictureBinding import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.onboarding.OnboardingAction @@ -39,10 +40,11 @@ import javax.inject.Inject class FtueAuthChooseProfilePictureFragment @Inject constructor( private val activeSessionHolder: ActiveSessionHolder, - colorProvider: ColorProvider + colorProvider: ColorProvider, + clock: Clock, ) : AbstractFtueAuthFragment(), GalleryOrCameraDialogHelper.Listener { - private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider) + private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock) private val avatarRenderer: AvatarRenderer by lazy { requireContext().singletonEntryPoint().avatarRenderer() } override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueProfilePictureBinding { diff --git a/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt b/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt index ae03b5345a..91292e42e5 100644 --- a/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt +++ b/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt @@ -24,6 +24,7 @@ import android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS import com.tapadoo.alerter.Alerter import im.vector.app.R import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.core.time.Clock import im.vector.app.core.utils.isAnimationDisabled import im.vector.app.features.analytics.ui.consent.AnalyticsOptInActivity import im.vector.app.features.pin.PinActivity @@ -41,7 +42,9 @@ import javax.inject.Singleton * will be back in the queue in first position. */ @Singleton -class PopupAlertManager @Inject constructor() { +class PopupAlertManager @Inject constructor( + private val clock: Clock, +) { companion object { const val INCOMING_CALL_PRIORITY = Int.MAX_VALUE @@ -116,7 +119,7 @@ class PopupAlertManager @Inject constructor() { return } if (currentAlerter != null) { - if (currentAlerter!!.expirationTimestamp != null && System.currentTimeMillis() > currentAlerter!!.expirationTimestamp!!) { + if (currentAlerter!!.expirationTimestamp != null && clock.epochMillis() > currentAlerter!!.expirationTimestamp!!) { // this alert has expired, remove it // perform dismiss try { @@ -162,7 +165,7 @@ class PopupAlertManager @Inject constructor() { currentAlerter = next next?.let { if (!shouldBeDisplayedIn(next, currentActivity)) return - val currentTime = System.currentTimeMillis() + val currentTime = clock.epochMillis() if (next.expirationTimestamp != null && currentTime > next.expirationTimestamp!!) { // skip try { diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt index 2871513c1f..0603342bb1 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomFragment.kt @@ -37,6 +37,7 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider +import im.vector.app.core.time.Clock import im.vector.app.databinding.FragmentCreateRoomBinding import im.vector.app.features.navigation.Navigator import im.vector.app.features.roomdirectory.RoomDirectorySharedAction @@ -62,7 +63,8 @@ data class CreateRoomArgs( class CreateRoomFragment @Inject constructor( private val createRoomController: CreateRoomController, private val createSpaceController: CreateSubSpaceController, - colorProvider: ColorProvider + colorProvider: ColorProvider, + clock: Clock, ) : VectorBaseFragment(), CreateRoomController.Listener, GalleryOrCameraDialogHelper.Listener, @@ -74,7 +76,7 @@ class CreateRoomFragment @Inject constructor( private lateinit var roomJoinRuleSharedActionViewModel: RoomJoinRuleSharedActionViewModel - private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider) + private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock) override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentCreateRoomBinding { return FragmentCreateRoomBinding.inflate(inflater, container, false) @@ -166,7 +168,8 @@ class CreateRoomFragment @Inject constructor( } else { listOf(RoomJoinRules.INVITE, RoomJoinRules.PUBLIC) } - RoomJoinRuleBottomSheet.newInstance(state.roomJoinRules, + RoomJoinRuleBottomSheet.newInstance( + state.roomJoinRules, allowed.map { it.toOption(false) }, state.isSubSpace, state.parentSpaceSummary?.displayName diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt index eb69e36ba0..85151e1258 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt @@ -37,6 +37,7 @@ import im.vector.app.core.intent.getFilenameFromUri import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider +import im.vector.app.core.time.Clock import im.vector.app.core.utils.toast import im.vector.app.databinding.FragmentRoomSettingGenericBinding import im.vector.app.features.analytics.plan.MobileScreen @@ -57,7 +58,8 @@ import javax.inject.Inject class RoomSettingsFragment @Inject constructor( private val controller: RoomSettingsController, colorProvider: ColorProvider, - private val avatarRenderer: AvatarRenderer + private val avatarRenderer: AvatarRenderer, + clock: Clock, ) : VectorBaseFragment(), RoomSettingsController.Callback, @@ -70,7 +72,7 @@ class RoomSettingsFragment @Inject constructor( private lateinit var roomJoinRuleSharedActionViewModel: RoomJoinRuleSharedActionViewModel private val roomProfileArgs: RoomProfileArgs by args() - private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider) + private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock) override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomSettingGenericBinding { return FragmentRoomSettingGenericBinding.inflate(inflater, container, false) @@ -198,7 +200,8 @@ class RoomSettingsFragment @Inject constructor( RoomSettingsAction.SetAvatarAction( RoomSettingsViewState.AvatarAction.UpdateAvatar( newAvatarUri = uri, - newAvatarFileName = getFilenameFromUri(requireContext(), uri) ?: UUID.randomUUID().toString()) + newAvatarFileName = getFilenameFromUri(requireContext(), uri) ?: UUID.randomUUID().toString() + ) ) ) } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt index 6a115ad272..7e83046c36 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt @@ -30,6 +30,7 @@ import com.google.android.material.tabs.TabLayoutMediator import im.vector.app.R import im.vector.app.core.intent.getMimeTypeFromUri import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.time.Clock import im.vector.app.core.utils.saveMedia import im.vector.app.core.utils.shareMedia import im.vector.app.databinding.FragmentRoomUploadsBinding @@ -43,7 +44,8 @@ import javax.inject.Inject class RoomUploadsFragment @Inject constructor( private val avatarRenderer: AvatarRenderer, - private val notificationUtils: NotificationUtils + private val notificationUtils: NotificationUtils, + private val clock: Clock, ) : VectorBaseFragment() { private val roomProfileArgs: RoomProfileArgs by args() @@ -88,7 +90,8 @@ class RoomUploadsFragment @Inject constructor( file = it.file, title = it.title, mediaMimeType = getMimeTypeFromUri(requireContext(), it.file.toUri()), - notificationUtils = notificationUtils + notificationUtils = notificationUtils, + now = clock.epochMillis() ) }.onFailure { failure -> if (!isAdded) return@onFailure diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index 195072465b..ca42a07d50 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -26,6 +26,7 @@ import com.squareup.seismic.ShakeDetector import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.core.time.Clock import im.vector.app.features.disclaimer.SHARED_PREF_KEY import im.vector.app.features.homeserver.ServerUrlsRepository import im.vector.app.features.themes.ThemeUtils @@ -33,7 +34,10 @@ import org.matrix.android.sdk.api.extensions.tryOrNull import timber.log.Timber import javax.inject.Inject -class VectorPreferences @Inject constructor(private val context: Context) { +class VectorPreferences @Inject constructor( + private val context: Context, + private val clock: Clock, +) { companion object { const val SETTINGS_HELP_PREFERENCE_KEY = "SETTINGS_HELP_PREFERENCE_KEY" @@ -664,9 +668,9 @@ class VectorPreferences @Inject constructor(private val context: Context) { */ fun getMinMediasLastAccessTime(): Long { return when (getSelectedMediasSavingPeriod()) { - MEDIA_SAVING_3_DAYS -> System.currentTimeMillis() / 1000 - 3 * 24 * 60 * 60 - MEDIA_SAVING_1_WEEK -> System.currentTimeMillis() / 1000 - 7 * 24 * 60 * 60 - MEDIA_SAVING_1_MONTH -> System.currentTimeMillis() / 1000 - 30 * 24 * 60 * 60 + MEDIA_SAVING_3_DAYS -> clock.epochMillis() / 1000 - 3 * 24 * 60 * 60 + MEDIA_SAVING_1_WEEK -> clock.epochMillis() / 1000 - 7 * 24 * 60 * 60 + MEDIA_SAVING_1_MONTH -> clock.epochMillis() / 1000 - 30 * 24 * 60 * 60 MEDIA_SAVING_FOREVER -> 0 else -> 0 } @@ -872,8 +876,10 @@ class VectorPreferences @Inject constructor(private val context: Context) { * @return true if user should always appear offline */ fun userAlwaysAppearsOffline(): Boolean { - return defaultPrefs.getBoolean(SETTINGS_PRESENCE_USER_ALWAYS_APPEARS_OFFLINE, - getDefault(R.bool.settings_presence_user_always_appears_offline_default)) + return defaultPrefs.getBoolean( + SETTINGS_PRESENCE_USER_ALWAYS_APPEARS_OFFLINE, + getDefault(R.bool.settings_presence_user_always_appears_offline_default) + ) } /** @@ -1005,9 +1011,11 @@ class VectorPreferences @Inject constructor(private val context: Context) { } fun prefSpacesShowAllRoomInHome(): Boolean { - return defaultPrefs.getBoolean(SETTINGS_PREF_SPACE_SHOW_ALL_ROOM_IN_HOME, + return defaultPrefs.getBoolean( + SETTINGS_PREF_SPACE_SHOW_ALL_ROOM_IN_HOME, // migration of old property - !labsSpacesOnlyOrphansInHome()) + !labsSpacesOnlyOrphansInHome() + ) } /* diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt index 678356b05b..99acea79df 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt @@ -45,6 +45,7 @@ import im.vector.app.core.preference.UserAvatarPreference import im.vector.app.core.preference.VectorPreference import im.vector.app.core.preference.VectorSwitchPreference import im.vector.app.core.resources.ColorProvider +import im.vector.app.core.time.Clock import im.vector.app.core.utils.TextUtils import im.vector.app.core.utils.getSizeOfFiles import im.vector.app.core.utils.toast @@ -74,7 +75,8 @@ import java.util.UUID import javax.inject.Inject class VectorSettingsGeneralFragment @Inject constructor( - colorProvider: ColorProvider + colorProvider: ColorProvider, + clock: Clock, ) : VectorSettingsBaseFragment(), GalleryOrCameraDialogHelper.Listener { @@ -82,7 +84,7 @@ class VectorSettingsGeneralFragment @Inject constructor( override var titleRes = R.string.settings_general_title override val preferenceXmlRes = R.xml.vector_settings_general - private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider) + private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock) private val mUserSettingsCategory by lazy { findPreference(VectorPreferences.SETTINGS_USER_SETTINGS_PREFERENCE_KEY)!! diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt index cef68c01c1..4225cbdbec 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestsFragment.kt @@ -36,12 +36,15 @@ import im.vector.app.R import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.extensions.safeOpenOutputStream import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.time.Clock import im.vector.app.core.utils.selectTxtFileToWrite import im.vector.app.databinding.FragmentDevtoolKeyrequestsBinding import org.matrix.android.sdk.api.extensions.tryOrNull import javax.inject.Inject -class KeyRequestsFragment @Inject constructor() : VectorBaseFragment() { +class KeyRequestsFragment @Inject constructor( + private val clock: Clock, +) : VectorBaseFragment() { override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentDevtoolKeyrequestsBinding { return FragmentDevtoolKeyrequestsBinding.inflate(inflater, container, false) @@ -126,7 +129,7 @@ class KeyRequestsFragment @Inject constructor() : VectorBaseFragment(), SpaceDetailEpoxyController.Listener, GalleryOrCameraDialogHelper.Listener, OnBackPressed { @@ -42,7 +44,7 @@ class CreateSpaceDetailsFragment @Inject constructor( override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) = FragmentSpaceCreateGenericEpoxyFormBinding.inflate(layoutInflater, container, false) - private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider) + private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt index 57b1c97efb..0264fdabfc 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceSettingsFragment.kt @@ -38,7 +38,7 @@ import im.vector.app.core.intent.getFilenameFromUri import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider -import im.vector.app.core.resources.DrawableProvider +import im.vector.app.core.time.Clock import im.vector.app.core.utils.toast import im.vector.app.databinding.FragmentRoomSettingGenericBinding import im.vector.app.features.home.AvatarRenderer @@ -60,9 +60,9 @@ import javax.inject.Inject class SpaceSettingsFragment @Inject constructor( private val epoxyController: SpaceSettingsController, - private val colorProvider: ColorProvider, + colorProvider: ColorProvider, + clock: Clock, private val avatarRenderer: AvatarRenderer, - private val drawableProvider: DrawableProvider ) : VectorBaseFragment(), SpaceSettingsController.Callback, GalleryOrCameraDialogHelper.Listener, @@ -73,7 +73,7 @@ class SpaceSettingsFragment @Inject constructor( private lateinit var roomJoinRuleSharedActionViewModel: RoomJoinRuleSharedActionViewModel - private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider) + private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock) override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) = FragmentRoomSettingGenericBinding.inflate(inflater) @@ -236,7 +236,8 @@ class SpaceSettingsFragment @Inject constructor( RoomSettingsAction.SetAvatarAction( RoomSettingsViewState.AvatarAction.UpdateAvatar( newAvatarUri = uri, - newAvatarFileName = getFilenameFromUri(requireContext(), uri) ?: UUID.randomUUID().toString()) + newAvatarFileName = getFilenameFromUri(requireContext(), uri) ?: UUID.randomUUID().toString() + ) ) ) } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt index 291153ef2b..bb1f8db6ff 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt @@ -47,6 +47,7 @@ import org.matrix.android.sdk.api.session.identity.IdentityServiceListener import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.user.model.User import org.matrix.android.sdk.api.util.toMatrixItem +import kotlin.random.Random data class ThreePidUser( val email: String, @@ -142,7 +143,7 @@ class UserListViewModel @AssistedInject constructor( } private fun retryUserSearch(state: UserListViewState) { - identityServerUsersSearch.tryEmit(UserSearch(state.searchTerm, cacheBuster = System.currentTimeMillis())) + identityServerUsersSearch.tryEmit(UserSearch(state.searchTerm, cacheBuster = Random.nextLong())) } private fun handleSearchUsers(searchTerm: String) { diff --git a/vector/src/main/java/im/vector/app/features/voice/VoicePlayerHelper.kt b/vector/src/main/java/im/vector/app/features/voice/VoicePlayerHelper.kt index d2f7927d75..6c9b8d34c2 100644 --- a/vector/src/main/java/im/vector/app/features/voice/VoicePlayerHelper.kt +++ b/vector/src/main/java/im/vector/app/features/voice/VoicePlayerHelper.kt @@ -20,11 +20,13 @@ import android.content.Context import android.os.Build import com.arthenica.ffmpegkit.FFmpegKit import com.arthenica.ffmpegkit.ReturnCode +import im.vector.app.core.time.Clock import timber.log.Timber import java.io.File import javax.inject.Inject class VoicePlayerHelper @Inject constructor( + private val clock: Clock, context: Context ) { private val outputDirectory: File by lazy { @@ -46,9 +48,9 @@ class VoicePlayerHelper @Inject constructor( if (targetFile.exists()) { targetFile.delete() } - val start = System.currentTimeMillis() + val start = clock.epochMillis() val session = FFmpegKit.execute("-i \"${file.path}\" -c:a aac \"${targetFile.path}\"") - val duration = System.currentTimeMillis() - start + val duration = clock.epochMillis() - start Timber.d("Convert to mp4 in $duration ms. Size in bytes from ${file.length()} to ${targetFile.length()}") return when { ReturnCode.isSuccess(session.returnCode) -> { diff --git a/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderL.kt b/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderL.kt index 2d40f5f7a3..e5fd60dbc3 100644 --- a/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderL.kt +++ b/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderL.kt @@ -23,10 +23,14 @@ import com.arthenica.ffmpegkit.FFmpegKitConfig import com.arthenica.ffmpegkit.Level import com.arthenica.ffmpegkit.ReturnCode import im.vector.app.BuildConfig +import im.vector.app.core.time.Clock import timber.log.Timber import java.io.File -class VoiceRecorderL(context: Context) : AbstractVoiceRecorder(context, "mp4") { +class VoiceRecorderL( + context: Context, + private val clock: Clock, +) : AbstractVoiceRecorder(context, "mp4") { override fun setOutputFormat(mediaRecorder: MediaRecorder) { // Use AAC/MP4 format here mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) @@ -43,9 +47,9 @@ class VoiceRecorderL(context: Context) : AbstractVoiceRecorder(context, "mp4") { if (targetFile.exists()) { targetFile.delete() } - val start = System.currentTimeMillis() + val start = clock.epochMillis() val session = FFmpegKit.execute("-i \"${recordedFile.path}\" -c:a libvorbis \"${targetFile.path}\"") - val duration = System.currentTimeMillis() - start + val duration = clock.epochMillis() - start Timber.d("Convert to ogg in $duration ms. Size in bytes from ${recordedFile.length()} to ${targetFile.length()}") return when { ReturnCode.isSuccess(session.returnCode) -> { diff --git a/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt b/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt index 004d520a6f..0cee8f4f6e 100644 --- a/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt +++ b/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt @@ -18,16 +18,18 @@ package im.vector.app.features.voice import android.content.Context import android.os.Build +import im.vector.app.core.time.Clock import javax.inject.Inject class VoiceRecorderProvider @Inject constructor( - private val context: Context + private val context: Context, + private val clock: Clock, ) { fun provideVoiceRecorder(): VoiceRecorder { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { VoiceRecorderQ(context) } else { - VoiceRecorderL(context) + VoiceRecorderL(context, clock) } } }