From 0e3b8fdbb68e33094e3881c25a6bb00a8a9f269c Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Mon, 1 Mar 2021 16:39:46 +0100 Subject: [PATCH] Upload custom attachment with thread --- app/build.gradle | 1 - .../keepass/activities/IconPickerActivity.kt | 54 +++---------- .../AttachmentFileNotificationService.kt | 77 ++++--------------- .../keepass/tasks/BinaryStreamManager.kt | 66 ++++++++++++++++ .../keepass/tasks/IconUploadWorker.kt | 15 ---- .../keepass/viewmodels/IconPickerViewModel.kt | 34 +++++++- 6 files changed, 121 insertions(+), 126 deletions(-) create mode 100644 app/src/main/java/com/kunzisoft/keepass/tasks/BinaryStreamManager.kt delete mode 100644 app/src/main/java/com/kunzisoft/keepass/tasks/IconUploadWorker.kt diff --git a/app/build.gradle b/app/build.gradle index 4a473205c..00f160670 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -120,7 +120,6 @@ dependencies { // Lifecycle - LiveData - ViewModel - Coroutines implementation "androidx.core:core-ktx:1.3.2" implementation 'androidx.fragment:fragment-ktx:1.2.5' - implementation 'androidx.work:work-runtime-ktx:2.5.0' // WARNING: To upgrade with style, bug in edit text implementation 'com.google.android.material:material:1.1.0' // Database diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/IconPickerActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/IconPickerActivity.kt index 2a6544faf..f526b04a8 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/IconPickerActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/IconPickerActivity.kt @@ -20,11 +20,8 @@ package com.kunzisoft.keepass.activities import android.app.Activity -import android.content.ContentResolver import android.content.Intent -import android.net.Uri import android.os.Bundle -import android.util.Log import android.view.MenuItem import android.view.View import android.view.ViewGroup @@ -37,10 +34,8 @@ import com.kunzisoft.keepass.activities.helpers.SelectFileHelper import com.kunzisoft.keepass.activities.lock.LockingActivity import com.kunzisoft.keepass.activities.lock.resetAppTimeoutWhenViewFocusedOrChanged import com.kunzisoft.keepass.database.element.Database -import com.kunzisoft.keepass.database.element.database.BinaryFile import com.kunzisoft.keepass.database.element.icon.IconImage import com.kunzisoft.keepass.settings.PreferencesUtil -import com.kunzisoft.keepass.stream.readAllBytes import com.kunzisoft.keepass.utils.UriUtil import com.kunzisoft.keepass.view.updateLockPaddingLeft import com.kunzisoft.keepass.viewmodels.IconPickerViewModel @@ -111,6 +106,9 @@ class IconPickerActivity : LockingActivity() { }) finish() } + iconPickerViewModel.iconCustomAdded.observe(this) { _ -> + uploadButton.isEnabled = true + } } override fun onResume() { @@ -137,44 +135,6 @@ class IconPickerActivity : LockingActivity() { return super.onOptionsItemSelected(item) } - private fun buildNewIcon(iconToUploadUri: Uri) { - mDatabase?.buildNewCustomIcon(UriUtil.getBinaryDir(this))?.let { customIcon -> - uploadIconToDatabase(iconToUploadUri, customIcon.binaryFile, contentResolver, - { - - } - ) - iconPickerViewModel.addCustomIcon(customIcon) - } - } - - // TODO Encapsulate - fun uploadIconToDatabase(iconToUploadUri: Uri, - binaryFile: BinaryFile, - contentResolver: ContentResolver, - update: ((percent: Int)->Unit)? = null, - canceled: ()-> Boolean = { false }, - bufferSize: Int = DEFAULT_BUFFER_SIZE,) { - var dataUploaded = 0L - val fileSize = contentResolver.openFileDescriptor(iconToUploadUri, "r")?.statSize ?: 0 - UriUtil.getUriInputStream(contentResolver, iconToUploadUri)?.use { inputStream -> - Database.getInstance().loadedCipherKey?.let { binaryCipherKey -> - binaryFile.getGzipOutputDataStream(binaryCipherKey).use { outputStream -> - inputStream.readAllBytes(bufferSize, canceled) { buffer -> - outputStream.write(buffer) - dataUploaded += buffer.size - try { - val percentDownload = (100 * dataUploaded / fileSize).toInt() - update?.invoke(percentDownload) - } catch (e: Exception) { - Log.e("", "", e) - } - } - } - } - } - } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) @@ -184,7 +144,13 @@ class IconPickerActivity : LockingActivity() { if (documentFile.length() > MAX_ICON_SIZE) { // TODO Error Icon size too big } else { - buildNewIcon(iconToUploadUri) + mDatabase?.let { database -> + iconPickerViewModel.addCustomIcon(database, + contentResolver, + UriUtil.getBinaryDir(this), + iconToUploadUri) + uploadButton.isEnabled = false + } } } } diff --git a/app/src/main/java/com/kunzisoft/keepass/services/AttachmentFileNotificationService.kt b/app/src/main/java/com/kunzisoft/keepass/services/AttachmentFileNotificationService.kt index a97555d86..2df2a9e0c 100644 --- a/app/src/main/java/com/kunzisoft/keepass/services/AttachmentFileNotificationService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/services/AttachmentFileNotificationService.kt @@ -29,13 +29,10 @@ import android.util.Log import androidx.documentfile.provider.DocumentFile import com.kunzisoft.keepass.R import com.kunzisoft.keepass.database.element.Attachment -import com.kunzisoft.keepass.database.element.Database -import com.kunzisoft.keepass.database.element.database.BinaryFile import com.kunzisoft.keepass.model.AttachmentState import com.kunzisoft.keepass.model.EntryAttachmentState import com.kunzisoft.keepass.model.StreamDirection -import com.kunzisoft.keepass.stream.readAllBytes -import com.kunzisoft.keepass.utils.UriUtil +import com.kunzisoft.keepass.tasks.BinaryStreamManager import kotlinx.coroutines.* import java.util.* import java.util.concurrent.CopyOnWriteArrayList @@ -347,24 +344,27 @@ class AttachmentFileNotificationService: LockNotificationService() { when (streamDirection) { StreamDirection.UPLOAD -> { - uploadToDatabase( + BinaryStreamManager.uploadToDatabase( attachmentNotification.uri, attachment.binaryFile, - contentResolver, 1024, + contentResolver, + { percent -> + publishProgress(percent) + }, { // Cancellation downloadState == AttachmentState.CANCELED } - ) { percent -> - publishProgress(percent) - } + ) } StreamDirection.DOWNLOAD -> { - downloadFromDatabase( + BinaryStreamManager.downloadFromDatabase( attachmentNotification.uri, attachment.binaryFile, - contentResolver, 1024) { percent -> - publishProgress(percent) - } + contentResolver, + { percent -> + publishProgress(percent) + } + ) } } } catch (e: Exception) { @@ -396,57 +396,6 @@ class AttachmentFileNotificationService: LockNotificationService() { attachmentNotification.entryAttachmentState.downloadState = AttachmentState.CANCELED } - fun downloadFromDatabase(attachmentToUploadUri: Uri, - binaryFile: BinaryFile, - contentResolver: ContentResolver, - bufferSize: Int = DEFAULT_BUFFER_SIZE, - update: ((percent: Int)->Unit)? = null) { - var dataDownloaded = 0L - val fileSize = binaryFile.length - UriUtil.getUriOutputStream(contentResolver, attachmentToUploadUri)?.use { outputStream -> - Database.getInstance().loadedCipherKey?.let { binaryCipherKey -> - binaryFile.getUnGzipInputDataStream(binaryCipherKey).use { inputStream -> - inputStream.readAllBytes(bufferSize) { buffer -> - outputStream.write(buffer) - dataDownloaded += buffer.size - try { - val percentDownload = (100 * dataDownloaded / fileSize).toInt() - update?.invoke(percentDownload) - } catch (e: Exception) { - Log.e(TAG, "", e) - } - } - } - } - } - } - - fun uploadToDatabase(attachmentFromDownloadUri: Uri, - binaryFile: BinaryFile, - contentResolver: ContentResolver, - bufferSize: Int = DEFAULT_BUFFER_SIZE, - canceled: ()-> Boolean = { false }, - update: ((percent: Int)->Unit)? = null) { - var dataUploaded = 0L - val fileSize = contentResolver.openFileDescriptor(attachmentFromDownloadUri, "r")?.statSize ?: 0 - UriUtil.getUriInputStream(contentResolver, attachmentFromDownloadUri)?.use { inputStream -> - Database.getInstance().loadedCipherKey?.let { binaryCipherKey -> - binaryFile.getGzipOutputDataStream(binaryCipherKey).use { outputStream -> - inputStream.readAllBytes(bufferSize, canceled) { buffer -> - outputStream.write(buffer) - dataUploaded += buffer.size - try { - val percentDownload = (100 * dataUploaded / fileSize).toInt() - update?.invoke(percentDownload) - } catch (e: Exception) { - Log.e(TAG, "", e) - } - } - } - } - } - } - private fun publishProgress(percent: Int) { // Publish progress val currentTime = System.currentTimeMillis() diff --git a/app/src/main/java/com/kunzisoft/keepass/tasks/BinaryStreamManager.kt b/app/src/main/java/com/kunzisoft/keepass/tasks/BinaryStreamManager.kt new file mode 100644 index 000000000..c14ea759a --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/tasks/BinaryStreamManager.kt @@ -0,0 +1,66 @@ +package com.kunzisoft.keepass.tasks + +import android.content.ContentResolver +import android.net.Uri +import android.util.Log +import com.kunzisoft.keepass.database.element.Database +import com.kunzisoft.keepass.database.element.database.BinaryFile +import com.kunzisoft.keepass.stream.readAllBytes +import com.kunzisoft.keepass.utils.UriUtil + +object BinaryStreamManager { + + fun downloadFromDatabase(attachmentToUploadUri: Uri, + binaryFile: BinaryFile, + contentResolver: ContentResolver, + update: ((percent: Int)->Unit)? = null, + canceled: ()-> Boolean = { false }, + bufferSize: Int = DEFAULT_BUFFER_SIZE) { + var dataDownloaded = 0L + val fileSize = binaryFile.length + UriUtil.getUriOutputStream(contentResolver, attachmentToUploadUri)?.use { outputStream -> + Database.getInstance().loadedCipherKey?.let { binaryCipherKey -> + binaryFile.getUnGzipInputDataStream(binaryCipherKey).use { inputStream -> + inputStream.readAllBytes(bufferSize, canceled) { buffer -> + outputStream.write(buffer) + dataDownloaded += buffer.size + try { + val percentDownload = (100 * dataDownloaded / fileSize).toInt() + update?.invoke(percentDownload) + } catch (e: Exception) { + Log.e(TAG, "", e) + } + } + } + } + } + } + + fun uploadToDatabase(attachmentFromDownloadUri: Uri, + binaryFile: BinaryFile, + contentResolver: ContentResolver, + update: ((percent: Int)->Unit)? = null, + canceled: ()-> Boolean = { false }, + bufferSize: Int = DEFAULT_BUFFER_SIZE) { + var dataUploaded = 0L + val fileSize = contentResolver.openFileDescriptor(attachmentFromDownloadUri, "r")?.statSize ?: 0 + UriUtil.getUriInputStream(contentResolver, attachmentFromDownloadUri)?.use { inputStream -> + Database.getInstance().loadedCipherKey?.let { binaryCipherKey -> + binaryFile.getGzipOutputDataStream(binaryCipherKey).use { outputStream -> + inputStream.readAllBytes(bufferSize, canceled) { buffer -> + outputStream.write(buffer) + dataUploaded += buffer.size + try { + val percentDownload = (100 * dataUploaded / fileSize).toInt() + update?.invoke(percentDownload) + } catch (e: Exception) { + Log.e(TAG, "", e) + } + } + } + } + } + } + + private val TAG = BinaryStreamManager::class.java.name +} \ No newline at end of file diff --git a/app/src/main/java/com/kunzisoft/keepass/tasks/IconUploadWorker.kt b/app/src/main/java/com/kunzisoft/keepass/tasks/IconUploadWorker.kt deleted file mode 100644 index f226ad05d..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/tasks/IconUploadWorker.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.kunzisoft.keepass.tasks - -import android.content.Context -import androidx.work.Worker -import androidx.work.WorkerParameters - -class IconUploadWorker(appContext: Context, workerParams: WorkerParameters): - Worker(appContext, workerParams) { - override fun doWork(): Result { - - //uploadImages() - - return Result.success() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/kunzisoft/keepass/viewmodels/IconPickerViewModel.kt b/app/src/main/java/com/kunzisoft/keepass/viewmodels/IconPickerViewModel.kt index 5697ca86f..f31ea80a6 100644 --- a/app/src/main/java/com/kunzisoft/keepass/viewmodels/IconPickerViewModel.kt +++ b/app/src/main/java/com/kunzisoft/keepass/viewmodels/IconPickerViewModel.kt @@ -1,12 +1,20 @@ package com.kunzisoft.keepass.viewmodels +import android.content.ContentResolver +import android.net.Uri import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.element.icon.IconImageCustom import com.kunzisoft.keepass.database.element.icon.IconImageStandard +import com.kunzisoft.keepass.tasks.BinaryStreamManager +import kotlinx.coroutines.* +import java.io.File class IconPickerViewModel: ViewModel() { + private val mainScope = CoroutineScope(Dispatchers.Main) + val iconStandardSelected: MutableLiveData by lazy { MutableLiveData() } @@ -27,7 +35,29 @@ class IconPickerViewModel: ViewModel() { iconCustomSelected.value = icon } - fun addCustomIcon(icon: IconImageCustom) { - iconCustomAdded.value = icon + fun addCustomIcon(database: Database, + contentResolver: ContentResolver, + iconDir: File, + iconToUploadUri: Uri) { + mainScope.launch { + withContext(Dispatchers.IO) { + // on Progress with thread + val asyncResult: Deferred = async { + database.buildNewCustomIcon(iconDir)?.let { customIcon -> + BinaryStreamManager.uploadToDatabase( + iconToUploadUri, + customIcon.binaryFile, + contentResolver + ) + customIcon + } + } + withContext(Dispatchers.Main) { + asyncResult.await()?.let { customIcon -> + iconCustomAdded.value = customIcon + } + } + } + } } } \ No newline at end of file