Attachment download as coroutine

This commit is contained in:
J-Jamet
2020-08-06 16:35:15 +02:00
parent cb82ef8703
commit 78ddb0533d
2 changed files with 91 additions and 105 deletions

View File

@@ -20,6 +20,7 @@
package com.kunzisoft.keepass.notifications package com.kunzisoft.keepass.notifications
import android.app.PendingIntent import android.app.PendingIntent
import android.content.ContentResolver
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Binder import android.os.Binder
@@ -29,7 +30,8 @@ import androidx.documentfile.provider.DocumentFile
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.model.AttachmentState import com.kunzisoft.keepass.model.AttachmentState
import com.kunzisoft.keepass.model.EntryAttachment import com.kunzisoft.keepass.model.EntryAttachment
import com.kunzisoft.keepass.tasks.AttachmentFileAsyncTask import com.kunzisoft.keepass.timeout.TimeoutHelper
import kotlinx.coroutines.*
import java.util.* import java.util.*
import kotlin.collections.HashMap import kotlin.collections.HashMap
@@ -41,6 +43,8 @@ class AttachmentFileNotificationService: LockNotificationService() {
private var mActionTaskBinder = ActionTaskBinder() private var mActionTaskBinder = ActionTaskBinder()
private var mActionTaskListeners = LinkedList<ActionTaskListener>() private var mActionTaskListeners = LinkedList<ActionTaskListener>()
private val mainScope = CoroutineScope(Dispatchers.Main)
inner class ActionTaskBinder: Binder() { inner class ActionTaskBinder: Binder() {
fun getService(): AttachmentFileNotificationService = this@AttachmentFileNotificationService fun getService(): AttachmentFileNotificationService = this@AttachmentFileNotificationService
@@ -99,7 +103,9 @@ class AttachmentFileNotificationService: LockNotificationService() {
intent.getParcelableExtra<EntryAttachment>(ATTACHMENT_KEY)?.let { entryAttachment -> intent.getParcelableExtra<EntryAttachment>(ATTACHMENT_KEY)?.let { entryAttachment ->
val attachmentNotification = AttachmentNotification(nextNotificationId, entryAttachment) val attachmentNotification = AttachmentNotification(nextNotificationId, entryAttachment)
downloadFileUris[downloadFileUri] = attachmentNotification downloadFileUris[downloadFileUri] = attachmentNotification
AttachmentFileAsyncTask(downloadFileUri,
mainScope.launch {
AttachmentFileActionClass(downloadFileUri,
attachmentNotification, attachmentNotification,
contentResolver).apply { contentResolver).apply {
onUpdate = { uri, attachment, notificationIdAttach -> onUpdate = { uri, attachment, notificationIdAttach ->
@@ -108,7 +114,8 @@ class AttachmentFileNotificationService: LockNotificationService() {
actionListener.onAttachmentProgress(downloadFileUri, attachment) actionListener.onAttachmentProgress(downloadFileUri, attachment)
} }
} }
}.execute() }.executeAction()
}
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Unable to download $downloadFileUri", e) Log.e(TAG, "Unable to download $downloadFileUri", e)
@@ -202,9 +209,9 @@ class AttachmentFileNotificationService: LockNotificationService() {
super.onDestroy() super.onDestroy()
} }
data class AttachmentNotification(var notificationId: Int, private data class AttachmentNotification(var notificationId: Int,
var entryAttachment: EntryAttachment, var entryAttachment: EntryAttachment,
var attachmentTask: AttachmentFileAsyncTask? = null) { var attachmentTask: AttachmentFileActionClass? = null) {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (javaClass != other?.javaClass) return false if (javaClass != other?.javaClass) return false
@@ -221,6 +228,78 @@ class AttachmentFileNotificationService: LockNotificationService() {
} }
} }
private class AttachmentFileActionClass(
private val fileUri: Uri,
private val attachmentNotification: AttachmentNotification,
private val contentResolver: ContentResolver) {
private val updateMinFrequency = 1000
private var previousSaveTime = System.currentTimeMillis()
var onUpdate: ((Uri, EntryAttachment, Int)->Unit)? = null
suspend fun executeAction() {
TimeoutHelper.temporarilyDisableTimeout()
// on pre execute
attachmentNotification.attachmentTask = this
attachmentNotification.entryAttachment.apply {
downloadState = AttachmentState.START
downloadProgression = 0
}
onUpdate?.invoke(fileUri,
attachmentNotification.entryAttachment,
attachmentNotification.notificationId)
withContext(Dispatchers.IO) {
// on Progress with thread
val asyncResult: Deferred<Boolean> = async {
var progressResult = true
try {
attachmentNotification.entryAttachment.apply {
downloadState = AttachmentState.IN_PROGRESS
binaryAttachment.download(fileUri, contentResolver, 1024) { percent ->
// Publish progress
val currentTime = System.currentTimeMillis()
if (previousSaveTime + updateMinFrequency < currentTime) {
attachmentNotification.entryAttachment.apply {
downloadState = AttachmentState.IN_PROGRESS
downloadProgression = percent
}
onUpdate?.invoke(fileUri,
attachmentNotification.entryAttachment,
attachmentNotification.notificationId)
Log.d(TAG, "Download file $fileUri : $percent%")
previousSaveTime = currentTime
}
}
}
} catch (e: Exception) {
progressResult = false
}
progressResult
}
// on post execute
withContext(Dispatchers.Main) {
val result = asyncResult.await()
attachmentNotification.attachmentTask = null
attachmentNotification.entryAttachment.apply {
downloadState = if (result) AttachmentState.COMPLETE else AttachmentState.ERROR
downloadProgression = 100
}
onUpdate?.invoke(fileUri,
attachmentNotification.entryAttachment,
attachmentNotification.notificationId)
}
}
}
companion object {
private val TAG = AttachmentFileActionClass::class.java.name
}
}
companion object { companion object {
private val TAG = AttachmentFileNotificationService::javaClass.name private val TAG = AttachmentFileNotificationService::javaClass.name

View File

@@ -1,93 +0,0 @@
/*
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePassDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.tasks
import android.content.ContentResolver
import android.net.Uri
import android.os.AsyncTask
import android.util.Log
import com.kunzisoft.keepass.model.AttachmentState
import com.kunzisoft.keepass.model.EntryAttachment
import com.kunzisoft.keepass.notifications.AttachmentFileNotificationService
class AttachmentFileAsyncTask(
private val fileUri: Uri,
private val attachmentNotification: AttachmentFileNotificationService.AttachmentNotification,
private val contentResolver: ContentResolver)
: AsyncTask<Void, Int, Boolean>() {
private val updateMinFrequency = 1000
private var previousSaveTime = System.currentTimeMillis()
var onUpdate: ((Uri, EntryAttachment, Int)->Unit)? = null
override fun onPreExecute() {
super.onPreExecute()
attachmentNotification.attachmentTask = this
attachmentNotification.entryAttachment.apply {
downloadState = AttachmentState.START
downloadProgression = 0
}
onUpdate?.invoke(fileUri, attachmentNotification.entryAttachment, attachmentNotification.notificationId)
}
override fun doInBackground(vararg params: Void?): Boolean {
try {
attachmentNotification.entryAttachment.apply {
downloadState = AttachmentState.IN_PROGRESS
binaryAttachment.download(fileUri, contentResolver, 1024) { percent ->
publishProgress(percent)
}
}
} catch (e: Exception) {
return false
}
return true
}
override fun onProgressUpdate(vararg values: Int?) {
super.onProgressUpdate(*values)
val percent = values[0] ?: 0
val currentTime = System.currentTimeMillis()
if (previousSaveTime + updateMinFrequency < currentTime) {
attachmentNotification.entryAttachment.apply {
downloadState = AttachmentState.IN_PROGRESS
downloadProgression = percent
}
onUpdate?.invoke(fileUri, attachmentNotification.entryAttachment, attachmentNotification.notificationId)
Log.d(TAG, "Download file $fileUri : $percent%")
previousSaveTime = currentTime
}
}
override fun onPostExecute(result: Boolean) {
super.onPostExecute(result)
attachmentNotification.attachmentTask = null
attachmentNotification.entryAttachment.apply {
downloadState = if (result) AttachmentState.COMPLETE else AttachmentState.ERROR
downloadProgression = 100
}
onUpdate?.invoke(fileUri, attachmentNotification.entryAttachment, attachmentNotification.notificationId)
}
companion object {
private val TAG = AttachmentFileAsyncTask::class.java.name
}
}