From c79c7fbf77d84ae9dc7cd0ef9a27a23b7136e194 Mon Sep 17 00:00:00 2001 From: Sean Weiser <125889608+sean-livefront@users.noreply.github.com> Date: Thu, 1 Feb 2024 14:52:29 -0600 Subject: [PATCH] BIT-1527: Wrap FileManager methods in io context (#945) --- .../data/vault/manager/FileManager.kt | 2 +- .../data/vault/manager/FileManagerImpl.kt | 90 +++++++++++-------- .../vault/manager/di/VaultManagerModule.kt | 2 + .../vault/repository/VaultRepositoryTest.kt | 16 ++-- 4 files changed, 62 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/FileManager.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/FileManager.kt index 0307ea6997..a721427697 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/FileManager.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/FileManager.kt @@ -31,5 +31,5 @@ interface FileManager { /** * Reads the [fileUri] into memory and returns the raw [ByteArray] */ - fun uriToByteArray(fileUri: Uri): ByteArray + suspend fun uriToByteArray(fileUri: Uri): ByteArray } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/FileManagerImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/FileManagerImpl.kt index a652334489..64bec4075c 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/FileManagerImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/FileManagerImpl.kt @@ -3,8 +3,10 @@ package com.x8bit.bitwarden.data.vault.manager import android.content.Context import android.net.Uri import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage +import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager import com.x8bit.bitwarden.data.vault.datasource.network.service.DownloadService import com.x8bit.bitwarden.data.vault.manager.model.DownloadResult +import kotlinx.coroutines.withContext import okio.use import java.io.ByteArrayOutputStream import java.io.File @@ -24,10 +26,13 @@ private const val BUFFER_SIZE: Int = 1024 class FileManagerImpl( private val context: Context, private val downloadService: DownloadService, + private val dispatcherManager: DispatcherManager, ) : FileManager { override suspend fun deleteFile(file: File) { - file.delete() + withContext(dispatcherManager.io) { + file.delete() + } } @Suppress("NestedBlockDepth", "ReturnCount") @@ -41,22 +46,25 @@ class FileManagerImpl( // Create a temporary file in cache to write to val file = File(context.cacheDir, UUID.randomUUID().toString()) - val stream = response.byteStream() - stream.use { - val buffer = ByteArray(BUFFER_SIZE) - var progress = 0 - FileOutputStream(file).use { fos -> - @Suppress("TooGenericExceptionCaught") - try { - var read = stream.read(buffer) - while (read > 0) { - fos.write(buffer, 0, read) - progress += read - read = stream.read(buffer) + + withContext(dispatcherManager.io) { + val stream = response.byteStream() + stream.use { + val buffer = ByteArray(BUFFER_SIZE) + var progress = 0 + FileOutputStream(file).use { fos -> + @Suppress("TooGenericExceptionCaught") + try { + var read = stream.read(buffer) + while (read > 0) { + fos.write(buffer, 0, read) + progress += read + read = stream.read(buffer) + } + fos.flush() + } catch (e: RuntimeException) { + return@withContext DownloadResult.Failure } - fos.flush() - } catch (e: RuntimeException) { - return DownloadResult.Failure } } } @@ -68,37 +76,41 @@ class FileManagerImpl( override suspend fun fileToUri(fileUri: Uri, file: File): Boolean { @Suppress("TooGenericExceptionCaught") return try { - context - .contentResolver - .openOutputStream(fileUri) - ?.use { outputStream -> - FileInputStream(file).use { inputStream -> - val buffer = ByteArray(BUFFER_SIZE) - var length: Int - while (inputStream.read(buffer).also { length = it } != -1) { - outputStream.write(buffer, 0, length) + withContext(dispatcherManager.io) { + context + .contentResolver + .openOutputStream(fileUri) + ?.use { outputStream -> + FileInputStream(file).use { inputStream -> + val buffer = ByteArray(BUFFER_SIZE) + var length: Int + while (inputStream.read(buffer).also { length = it } != -1) { + outputStream.write(buffer, 0, length) + } } } - } + } true } catch (exception: RuntimeException) { false } } - override fun uriToByteArray(fileUri: Uri): ByteArray = - 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) + override suspend fun uriToByteArray(fileUri: Uri): ByteArray = + 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() } - outputStream.toByteArray() } - } - ?: byteArrayOf() + ?: byteArrayOf() + } } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/di/VaultManagerModule.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/di/VaultManagerModule.kt index 8c57d721d7..6ad86a8a27 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/di/VaultManagerModule.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/manager/di/VaultManagerModule.kt @@ -35,9 +35,11 @@ object VaultManagerModule { fun provideFileManager( @ApplicationContext context: Context, downloadService: DownloadService, + dispatcherManager: DispatcherManager, ): FileManager = FileManagerImpl( context = context, downloadService = downloadService, + dispatcherManager = dispatcherManager, ) @Provides diff --git a/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt index 753f79cedd..c1f46a78c2 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt @@ -2347,7 +2347,7 @@ class VaultRepositoryTest { coEvery { vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView) } returns mockSdkSend.asSuccess() - every { fileManager.uriToByteArray(any()) } returns byteArray + coEvery { fileManager.uriToByteArray(any()) } returns byteArray coEvery { vaultSdkSource.encryptBuffer( userId = userId, @@ -2384,7 +2384,7 @@ class VaultRepositoryTest { coEvery { vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView) } returns mockSdkSend.asSuccess() - every { fileManager.uriToByteArray(any()) } returns byteArray + coEvery { fileManager.uriToByteArray(any()) } returns byteArray coEvery { vaultSdkSource.encryptBuffer( userId = userId, @@ -2429,7 +2429,7 @@ class VaultRepositoryTest { coEvery { vaultSdkSource.encryptSend(userId = userId, sendView = mockSendView) } returns mockSdkSend.asSuccess() - every { fileManager.uriToByteArray(any()) } returns byteArray + coEvery { fileManager.uriToByteArray(any()) } returns byteArray coEvery { vaultSdkSource.encryptBuffer( userId = userId, @@ -3052,7 +3052,7 @@ class VaultRepositoryTest { coEvery { vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView) } returns mockCipher.asSuccess() - every { fileManager.uriToByteArray(fileUri = mockUri) } returns mockByteArray + coEvery { fileManager.uriToByteArray(fileUri = mockUri) } returns mockByteArray coEvery { vaultSdkSource.encryptAttachment( userId = userId, @@ -3096,7 +3096,7 @@ class VaultRepositoryTest { coEvery { vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView) } returns mockCipher.asSuccess() - every { fileManager.uriToByteArray(fileUri = mockUri) } returns mockByteArray + coEvery { fileManager.uriToByteArray(fileUri = mockUri) } returns mockByteArray coEvery { vaultSdkSource.encryptAttachment( userId = userId, @@ -3151,7 +3151,7 @@ class VaultRepositoryTest { coEvery { vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView) } returns mockCipher.asSuccess() - every { fileManager.uriToByteArray(fileUri = mockUri) } returns mockByteArray + coEvery { fileManager.uriToByteArray(fileUri = mockUri) } returns mockByteArray coEvery { vaultSdkSource.encryptAttachment( userId = userId, @@ -3213,7 +3213,7 @@ class VaultRepositoryTest { coEvery { vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView) } returns mockCipher.asSuccess() - every { fileManager.uriToByteArray(fileUri = mockUri) } returns mockByteArray + coEvery { fileManager.uriToByteArray(fileUri = mockUri) } returns mockByteArray coEvery { vaultSdkSource.encryptAttachment( userId = userId, @@ -3284,7 +3284,7 @@ class VaultRepositoryTest { coEvery { vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView) } returns mockCipher.asSuccess() - every { fileManager.uriToByteArray(fileUri = mockUri) } returns mockByteArray + coEvery { fileManager.uriToByteArray(fileUri = mockUri) } returns mockByteArray coEvery { vaultSdkSource.encryptAttachment( userId = userId,