[PM-31370] Refactor stringToUri and consolidate FileManager (#6432)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Patrick Honkonen 2026-01-28 16:37:24 -05:00 committed by GitHub
parent 7717a09c06
commit 3d974d710c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 17 additions and 109 deletions

View File

@ -1,19 +0,0 @@
package com.bitwarden.authenticator.data.authenticator.manager
import android.net.Uri
/**
* Manages reading and writing files.
*/
interface FileManager {
/**
* Writes the given [dataString] to disk at the provided [fileUri]
*/
suspend fun stringToUri(fileUri: Uri, dataString: String): Boolean
/**
* Reads the [fileUri] into memory. A successful result will contain the raw [ByteArray].
*/
suspend fun uriToByteArray(fileUri: Uri): Result<ByteArray>
}

View File

@ -1,58 +0,0 @@
package com.bitwarden.authenticator.data.authenticator.manager
import android.content.Context
import android.net.Uri
import com.bitwarden.core.data.manager.dispatcher.DispatcherManager
import kotlinx.coroutines.withContext
import java.io.ByteArrayOutputStream
/**
* The buffer size to be used when reading from an input stream.
*/
private const val BUFFER_SIZE: Int = 1024
/**
* Manages reading and writing files.
*/
class FileManagerImpl(
private val context: Context,
private val dispatcherManager: DispatcherManager,
) : FileManager {
override suspend fun stringToUri(fileUri: Uri, dataString: String): Boolean {
@Suppress("TooGenericExceptionCaught")
return try {
withContext(dispatcherManager.io) {
context
.contentResolver
.openOutputStream(fileUri)
?.use { outputStream ->
outputStream.write(dataString.toByteArray())
}
}
true
} catch (exception: RuntimeException) {
false
}
}
override suspend fun uriToByteArray(fileUri: Uri): Result<ByteArray> =
runCatching {
withContext(dispatcherManager.io) {
context
.contentResolver
.openInputStream(fileUri)
?.use { inputStream ->
ByteArrayOutputStream().use { outputStream ->
val buffer = ByteArray(BUFFER_SIZE)
var length: Int
while (inputStream.read(buffer).also { length = it } != -1) {
outputStream.write(buffer, 0, length)
}
outputStream.toByteArray()
}
}
?: throw IllegalStateException("Stream has crashed")
}
}
}

View File

@ -1,16 +1,11 @@
package com.bitwarden.authenticator.data.authenticator.manager.di
import android.content.Context
import com.bitwarden.authenticator.data.authenticator.datasource.sdk.AuthenticatorSdkSource
import com.bitwarden.authenticator.data.authenticator.manager.FileManager
import com.bitwarden.authenticator.data.authenticator.manager.FileManagerImpl
import com.bitwarden.authenticator.data.authenticator.manager.TotpCodeManager
import com.bitwarden.authenticator.data.authenticator.manager.TotpCodeManagerImpl
import com.bitwarden.core.data.manager.dispatcher.DispatcherManager
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import java.time.Clock
import javax.inject.Singleton
@ -22,21 +17,10 @@ import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
object AuthenticatorManagerModule {
@Provides
@Singleton
fun providerFileManager(
@ApplicationContext context: Context,
dispatcherManager: DispatcherManager,
): FileManager = FileManagerImpl(
context = context,
dispatcherManager = dispatcherManager,
)
@Provides
@Singleton
fun provideTotpCodeManager(
authenticatorSdkSource: AuthenticatorSdkSource,
dispatcherManager: DispatcherManager,
clock: Clock,
): TotpCodeManager = TotpCodeManagerImpl(
authenticatorSdkSource = authenticatorSdkSource,

View File

@ -3,7 +3,6 @@ package com.bitwarden.authenticator.data.authenticator.repository
import android.net.Uri
import com.bitwarden.authenticator.data.authenticator.datasource.disk.AuthenticatorDiskSource
import com.bitwarden.authenticator.data.authenticator.datasource.disk.entity.AuthenticatorItemEntity
import com.bitwarden.authenticator.data.authenticator.manager.FileManager
import com.bitwarden.authenticator.data.authenticator.manager.TotpCodeManager
import com.bitwarden.authenticator.data.authenticator.manager.model.ExportJsonData
import com.bitwarden.authenticator.data.authenticator.manager.model.VerificationCodeItem
@ -27,6 +26,7 @@ import com.bitwarden.core.data.manager.dispatcher.DispatcherManager
import com.bitwarden.core.data.repository.model.DataState
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
import com.bitwarden.core.data.repository.util.map
import com.bitwarden.data.manager.file.FileManager
import com.bitwarden.ui.platform.model.FileData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi

View File

@ -1,7 +1,6 @@
package com.bitwarden.authenticator.data.authenticator.repository.di
import com.bitwarden.authenticator.data.authenticator.datasource.disk.AuthenticatorDiskSource
import com.bitwarden.authenticator.data.authenticator.manager.FileManager
import com.bitwarden.authenticator.data.authenticator.manager.TotpCodeManager
import com.bitwarden.authenticator.data.authenticator.repository.AuthenticatorRepository
import com.bitwarden.authenticator.data.authenticator.repository.AuthenticatorRepositoryImpl
@ -9,6 +8,7 @@ import com.bitwarden.authenticator.data.platform.manager.imports.ImportManager
import com.bitwarden.authenticator.data.platform.repository.SettingsRepository
import com.bitwarden.authenticatorbridge.manager.AuthenticatorBridgeManager
import com.bitwarden.core.data.manager.dispatcher.DispatcherManager
import com.bitwarden.data.manager.file.FileManager
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn

View File

@ -3,7 +3,7 @@ package com.bitwarden.authenticator.data.authenticator.repository
import app.cash.turbine.test
import com.bitwarden.authenticator.data.authenticator.datasource.disk.util.FakeAuthenticatorDiskSource
import com.bitwarden.authenticator.data.authenticator.datasource.entity.createMockAuthenticatorItemEntity
import com.bitwarden.authenticator.data.authenticator.manager.FileManager
import com.bitwarden.data.manager.file.FileManager
import com.bitwarden.authenticator.data.authenticator.manager.TotpCodeManager
import com.bitwarden.authenticator.data.authenticator.manager.model.VerificationCodeItem
import com.bitwarden.authenticator.data.authenticator.repository.model.AuthenticatorItem

View File

@ -17,6 +17,7 @@ import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.util.UUID
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
@ -108,21 +109,21 @@ internal class FileManagerImpl(
}
}
override suspend fun stringToUri(fileUri: Uri, dataString: String): Boolean {
@Suppress("TooGenericExceptionCaught")
return try {
withContext(dispatcherManager.io) {
context
.contentResolver
.openOutputStream(fileUri)
?.use { outputStream ->
outputStream.write(dataString.toByteArray())
override suspend fun stringToUri(fileUri: Uri, dataString: String): Boolean = try {
withContext(dispatcherManager.io) {
context
.contentResolver
.openOutputStream(fileUri)
?.use { outputStream ->
outputStream.writer().use {
it.write(dataString)
}
}
true
} catch (_: RuntimeException) {
false
true
}
?: false
}
} catch (_: IOException) {
false
}
override suspend fun uriToByteArray(fileUri: Uri): Result<ByteArray> =