@@ -20,13 +20,17 @@ import com.owncloud.android.lib.common.OwnCloudClientManagerFactory
2020import com.owncloud.android.lib.common.utils.Log_OC
2121import com.owncloud.android.operations.DownloadFileOperation
2222import com.owncloud.android.operations.DownloadType
23- import com.owncloud.android.ui.helpers.FileOperationsHelper
23+ import com.owncloud.android.utils.FileStorageUtils
2424import com.owncloud.android.utils.theme.ViewThemeUtils
2525import kotlinx.coroutines.Dispatchers
26+ import kotlinx.coroutines.delay
2627import kotlinx.coroutines.withContext
2728import java.util.concurrent.ConcurrentHashMap
2829
29- @Suppress(" LongMethod" , " TooGenericExceptionCaught" )
30+ /* *
31+ * Only used for downloading files in first level of the folder, not subfolders.
32+ */
33+ @Suppress(" LongMethod" , " TooGenericExceptionCaught" , " MagicNumber" )
3034class FolderDownloadWorker (
3135 private val accountManager : UserAccountManager ,
3236 private val context : Context ,
@@ -39,13 +43,11 @@ class FolderDownloadWorker(
3943 private const val TAG = " 📂" + " FolderDownloadWorker"
4044 const val FOLDER_ID = " FOLDER_ID"
4145 const val ACCOUNT_NAME = " ACCOUNT_NAME"
42-
43- private val pendingDownloads: MutableSet <Long > = ConcurrentHashMap .newKeySet<Long >()
44-
46+ private val pendingDownloads: MutableSet <Long > = ConcurrentHashMap .newKeySet()
4547 fun isDownloading (id : Long ): Boolean = pendingDownloads.contains(id)
4648 }
4749
48- private val notificationManager = FolderDownloadWorkerNotificationManager (context, viewThemeUtils)
50+ private val notificationManager = FolderDownloadWorkerNotificationManager (context, true , viewThemeUtils)
4951 private val folderDownloadEventBroadcaster = FolderDownloadEventBroadcaster (context, localBroadcastManager)
5052 private lateinit var storageManager: FileDataStorageManager
5153
@@ -58,88 +60,99 @@ class FolderDownloadWorker(
5860
5961 val accountName = inputData.getString(ACCOUNT_NAME )
6062 if (accountName == null ) {
61- Log_OC .e(TAG , " failed accountName cannot be null" )
63+ Log_OC .e(TAG , " failed: accountName cannot be null" )
6264 return Result .failure()
6365 }
6466
6567 val optionalUser = accountManager.getUser(accountName)
6668 if (optionalUser.isEmpty) {
67- Log_OC .e(TAG , " failed user is not present" )
69+ Log_OC .e(TAG , " failed: user is not present" )
6870 return Result .failure()
6971 }
7072
7173 val user = optionalUser.get()
7274 storageManager = FileDataStorageManager (user, context.contentResolver)
75+
7376 val folder = storageManager.getFileById(folderID)
7477 if (folder == null ) {
75- Log_OC .e(TAG , " failed folder cannot be nul " )
78+ Log_OC .e(TAG , " failed: folder cannot be null " )
7679 return Result .failure()
7780 }
7881
79- Log_OC .d(TAG , " 🕒 started for ${user.accountName} downloading ${folder.fileName} " )
82+ Log_OC .d(TAG , " 🕒 started for ${user.accountName} | folder= ${folder.fileName} " )
8083
8184 trySetForeground(folder)
82-
8385 folderDownloadEventBroadcaster.sendDownloadEnqueued(folder.fileId)
8486 pendingDownloads.add(folder.fileId)
8587
8688 val downloadHelper = FileDownloadHelper .instance()
8789
8890 return withContext(Dispatchers .IO ) {
8991 try {
90- val files = getFiles(folder, storageManager)
9192 val account = user.toOwnCloudAccount()
92- val client = OwnCloudClientManagerFactory .getDefaultSingleton().getClientFor(account, context)
93+ val client = OwnCloudClientManagerFactory .getDefaultSingleton()
94+ .getClientFor(account, context)
95+ val files = getFiles(folder, storageManager)
96+ if (files.isEmpty()) {
97+ Log_OC .d(TAG , " ✅ no files need downloading" )
98+ notificationManager.showCompletionNotification(folder.fileName, true )
99+ return @withContext Result .success()
100+ }
101+
102+ var overallSuccess = true
93103
94- var result = true
95104 files.forEachIndexed { index, file ->
96- if (! checkDiskSize(file)) {
105+ if (isStopped) {
106+ Log_OC .d(TAG , " ⚠️ worker stopped mid-download, aborting remaining files" )
97107 return @withContext Result .failure()
98108 }
99109
100- withContext(Dispatchers .Main ) {
101- val notification = notificationManager.getProgressNotification(
102- folder.fileName,
103- file.fileName,
104- index,
105- files.size
106- )
107- notificationManager.showNotification(notification)
108-
109- val foregroundInfo = notificationManager.getForegroundInfo(notification)
110- setForeground(foregroundInfo)
110+ if (! FileStorageUtils .checkIfEnoughSpace(folder)) {
111+ notificationManager.showNotAvailableDiskSpace()
112+ return @withContext Result .failure()
111113 }
112114
115+ notificationManager.showProgressNotification(
116+ folder.fileName,
117+ file.fileName,
118+ index,
119+ files.size
120+ )
121+
113122 val operation = DownloadFileOperation (user, file, context)
114123 val operationResult = operation.execute(client)
124+
115125 if (operationResult?.isSuccess == true && operation.downloadType == = DownloadType .DOWNLOAD ) {
116126 getOCFile(operation)?.let { ocFile ->
117127 downloadHelper.saveFile(ocFile, operation, storageManager)
118128 }
119129 }
120130
121- if (! operationResult.isSuccess) {
122- result = false
131+ if (operationResult?.isSuccess != true ) {
132+ Log_OC .w(TAG , " ⚠️ download failed for ${file.remotePath} : ${operationResult?.logMessage} " )
133+ overallSuccess = false
123134 }
124135 }
125136
126- withContext(Dispatchers .Main ) {
127- notificationManager.showCompletionNotification(folder.fileName, result)
128- }
137+ notificationManager.showCompletionNotification(folder.fileName, overallSuccess)
129138
130- if (result ) {
131- Log_OC .d(TAG , " ✅ completed" )
139+ if (overallSuccess ) {
140+ Log_OC .d(TAG , " ✅ completed successfully " )
132141 Result .success()
133142 } else {
134- Log_OC .d(TAG , " ❌ failed " )
143+ Log_OC .d(TAG , " ❌ completed with failures " )
135144 Result .failure()
136145 }
137146 } catch (e: Exception ) {
138- Log_OC .d(TAG , " ❌ failed reason: $e " )
147+ Log_OC .e(TAG , " ❌ unexpected failure: $e " )
148+ notificationManager.showCompletionNotification(folder.fileName, false )
139149 Result .failure()
140150 } finally {
141151 folderDownloadEventBroadcaster.sendDownloadCompleted(folder.fileId)
142152 pendingDownloads.remove(folder.fileId)
153+
154+ // delay so that user can see the error or success notification
155+ delay(2000 )
143156 notificationManager.dismiss()
144157 }
145158 }
@@ -155,11 +168,12 @@ class FolderDownloadWorker(
155168 return notificationManager.getForegroundInfo(null )
156169 }
157170
158- val folder = storageManager.getFileById(folderID) ? : return notificationManager.getForegroundInfo(null )
171+ val folder = storageManager.getFileById(folderID)
172+ ? : return notificationManager.getForegroundInfo(null )
159173
160- return notificationManager.getForegroundInfo(folder)
174+ notificationManager.getForegroundInfo(folder)
161175 } catch (e: Exception ) {
162- Log_OC .w(TAG , " ⚠️ Error getting foreground info: ${e.message} " )
176+ Log_OC .w(TAG , " ⚠️ error getting foreground info: ${e.message} " )
163177 notificationManager.getForegroundInfo(null )
164178 }
165179 }
@@ -169,34 +183,20 @@ class FolderDownloadWorker(
169183 val foregroundInfo = notificationManager.getForegroundInfo(folder)
170184 setForeground(foregroundInfo)
171185 } catch (e: Exception ) {
172- Log_OC .w(TAG , " ⚠️ Could not set foreground service: ${e.message} " )
186+ Log_OC .w(TAG , " ⚠️ could not set foreground service: ${e.message} " )
173187 }
174188 }
175189
176- private fun getOCFile (operation : DownloadFileOperation ): OCFile ? {
177- val file = operation.file?.fileId?.let { storageManager.getFileById(it) }
178- ? : storageManager.getFileByDecryptedRemotePath(operation.file?.remotePath)
179- ? : run {
180- Log_OC .e(TAG , " could not save ${operation.file?.remotePath} " )
181- return null
182- }
183-
184- return file
190+ private fun getOCFile (operation : DownloadFileOperation ): OCFile ? = operation.file?.fileId?.let {
191+ storageManager.getFileById(it)
185192 }
193+ ? : storageManager.getFileByDecryptedRemotePath(operation.file?.remotePath)
194+ ? : run {
195+ Log_OC .e(TAG , " could not resolve OCFile for save: ${operation.file?.remotePath} " )
196+ null
197+ }
186198
187199 private fun getFiles (folder : OCFile , storageManager : FileDataStorageManager ): List <OCFile > =
188200 storageManager.getFolderContent(folder, false )
189201 .filter { ! it.isFolder && ! it.isDown }
190-
191- private fun checkDiskSize (file : OCFile ): Boolean {
192- val fileSizeInByte = file.fileLength
193- val availableDiskSpace = FileOperationsHelper .getAvailableSpaceOnDevice()
194-
195- return if (availableDiskSpace < fileSizeInByte) {
196- notificationManager.showNotAvailableDiskSpace()
197- false
198- } else {
199- true
200- }
201- }
202202}
0 commit comments