DownloadTask.kt 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /*
  2. * Nextcloud Android client application
  3. *
  4. * @author Chris Narkiewicz
  5. * Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Affero General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. package com.nextcloud.client.files.downloader
  21. import android.content.ContentResolver
  22. import android.content.Context
  23. import com.nextcloud.client.core.IsCancelled
  24. import com.owncloud.android.datamodel.FileDataStorageManager
  25. import com.owncloud.android.datamodel.OCFile
  26. import com.owncloud.android.lib.common.OwnCloudClient
  27. import com.owncloud.android.operations.DownloadFileOperation
  28. import com.owncloud.android.utils.MimeTypeUtil
  29. import java.io.File
  30. /**
  31. * This runnable object encapsulates file download logic. It has been extracted to wrap
  32. * network operation and storage manager interactions, as those pose testing challenges
  33. * that cannot be addressed due to large number of dependencies.
  34. *
  35. * This design can be regarded as intermediary refactoring step.
  36. */
  37. class DownloadTask(
  38. val context: Context,
  39. val contentResolver: ContentResolver,
  40. val clientProvider: () -> OwnCloudClient
  41. ) {
  42. data class Result(val file: OCFile, val success: Boolean)
  43. /**
  44. * This class is a helper factory to to keep static dependencies
  45. * injection out of the downloader instance.
  46. *
  47. * @param context Context
  48. * @param clientProvider Provide client - this must be called on background thread
  49. * @param contentResolver content resovler used to access file storage
  50. */
  51. class Factory(
  52. private val context: Context,
  53. private val clientProvider: () -> OwnCloudClient,
  54. private val contentResolver: ContentResolver
  55. ) {
  56. fun create(): DownloadTask {
  57. return DownloadTask(context, contentResolver, clientProvider)
  58. }
  59. }
  60. fun download(request: Request, progress: (Int) -> Unit, isCancelled: IsCancelled): Result {
  61. val op = DownloadFileOperation(request.user.toPlatformAccount(), request.file, context)
  62. val client = clientProvider.invoke()
  63. val result = op.execute(client)
  64. if (result.isSuccess) {
  65. val storageManager = FileDataStorageManager(
  66. request.user.toPlatformAccount(),
  67. contentResolver
  68. )
  69. val file = saveDownloadedFile(op, storageManager)
  70. return Result(file, true)
  71. } else {
  72. return Result(request.file, false)
  73. }
  74. }
  75. private fun saveDownloadedFile(op: DownloadFileOperation, storageManager: FileDataStorageManager): OCFile {
  76. val file = storageManager.getFileById(op.getFile().getFileId()) as OCFile
  77. val syncDate = System.currentTimeMillis()
  78. file.lastSyncDateForProperties = syncDate
  79. file.lastSyncDateForData = syncDate
  80. file.isUpdateThumbnailNeeded = true
  81. file.modificationTimestamp = op.getModificationTimestamp()
  82. file.modificationTimestampAtLastSyncForData = op.getModificationTimestamp()
  83. file.etag = op.getEtag()
  84. file.mimeType = op.getMimeType()
  85. file.storagePath = op.getSavePath()
  86. file.fileLength = File(op.getSavePath()).length()
  87. file.remoteId = op.getFile().getRemoteId()
  88. storageManager.saveFile(file)
  89. if (MimeTypeUtil.isMedia(op.getMimeType())) {
  90. FileDataStorageManager.triggerMediaScan(file.storagePath)
  91. }
  92. return file
  93. }
  94. }