nextcloud-android/src/main/java/com/nextcloud/client/files/downloader/DownloadTask.kt

101 lines
3.9 KiB
Kotlin

/*
* Nextcloud Android client application
*
* @author Chris Narkiewicz
* Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.client.files.downloader
import android.content.ContentResolver
import android.content.Context
import com.nextcloud.client.core.IsCancelled
import com.owncloud.android.datamodel.FileDataStorageManager
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.lib.common.OwnCloudClient
import com.owncloud.android.operations.DownloadFileOperation
import com.owncloud.android.utils.MimeTypeUtil
import java.io.File
/**
* This runnable object encapsulates file download logic. It has been extracted to wrap
* network operation and storage manager interactions, as those pose testing challenges
* that cannot be addressed due to large number of dependencies.
*
* This design can be regarded as intermediary refactoring step.
*/
class DownloadTask(
val context: Context,
val contentResolver: ContentResolver,
val clientProvider: () -> OwnCloudClient
) {
data class Result(val file: OCFile, val success: Boolean)
/**
* This class is a helper factory to to keep static dependencies
* injection out of the downloader instance.
*
* @param context Context
* @param clientProvider Provide client - this must be called on background thread
* @param contentResolver content resovler used to access file storage
*/
class Factory(
private val context: Context,
private val clientProvider: () -> OwnCloudClient,
private val contentResolver: ContentResolver
) {
fun create(): DownloadTask {
return DownloadTask(context, contentResolver, clientProvider)
}
}
fun download(request: Request, progress: (Int) -> Unit, isCancelled: IsCancelled): Result {
val op = DownloadFileOperation(request.user.toPlatformAccount(), request.file, context)
val client = clientProvider.invoke()
val result = op.execute(client)
if (result.isSuccess) {
val storageManager = FileDataStorageManager(
request.user.toPlatformAccount(),
contentResolver
)
val file = saveDownloadedFile(op, storageManager)
return Result(file, true)
} else {
return Result(request.file, false)
}
}
private fun saveDownloadedFile(op: DownloadFileOperation, storageManager: FileDataStorageManager): OCFile {
val file = storageManager.getFileById(op.getFile().getFileId()) as OCFile
val syncDate = System.currentTimeMillis()
file.lastSyncDateForProperties = syncDate
file.lastSyncDateForData = syncDate
file.isUpdateThumbnailNeeded = true
file.modificationTimestamp = op.getModificationTimestamp()
file.modificationTimestampAtLastSyncForData = op.getModificationTimestamp()
file.etag = op.getEtag()
file.mimeType = op.getMimeType()
file.storagePath = op.getSavePath()
file.fileLength = File(op.getSavePath()).length()
file.remoteId = op.getFile().getRemoteId()
storageManager.saveFile(file)
if (MimeTypeUtil.isMedia(op.getMimeType())) {
FileDataStorageManager.triggerMediaScan(file.storagePath)
}
return file
}
}