Browse Source

Add folder download job

Signed-off-by: alperozturk <alper_ozturk@proton.me>
alperozturk 1 year ago
parent
commit
1e28130b5d

+ 21 - 3
app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt

@@ -29,8 +29,10 @@ import com.owncloud.android.datamodel.OCFile
 import com.owncloud.android.datamodel.UploadsStorageManager
 import com.owncloud.android.operations.DownloadFileOperation
 import com.owncloud.android.operations.DownloadType
+import com.owncloud.android.operations.SynchronizeFolderOperation
 import com.owncloud.android.utils.MimeTypeUtil
 import java.io.File
+import java.util.concurrent.atomic.AtomicBoolean
 import javax.inject.Inject
 
 class FileDownloadHelper {
@@ -56,12 +58,24 @@ class FileDownloadHelper {
     }
 
     fun isDownloading(user: User?, file: OCFile?): Boolean {
-        return user != null && file != null && backgroundJobManager.isStartFileDownloadJobScheduled(
+        if (user == null || file == null) {
+            return false
+        }
+
+        return backgroundJobManager.isStartFileDownloadJobScheduled(
             user,
             file
         )
     }
 
+    private fun isFolderDownloading(folder: OCFile): Boolean {
+        for ((id, status) in SynchronizeFolderOperation.folderDownloadStatusPair) {
+            return id == folder.fileId && status
+        }
+
+        return false
+    }
+
     fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) {
         if (user == null || file == null) return
         backgroundJobManager.cancelFilesDownloadJob(user, file)
@@ -117,8 +131,12 @@ class FileDownloadHelper {
         }
     }
 
-    fun downloadFile(user: User, ocFile: OCFile) {
-        downloadFile(user, ocFile, downloadType = DownloadType.DOWNLOAD)
+    fun downloadFolder(folder: OCFile, user: User, files: List<OCFile>) {
+        backgroundJobManager.startFolderDownloadJob(folder, user, files)
+    }
+
+    fun downloadFile(user: User, file: OCFile) {
+        downloadFile(user, file, downloadType = DownloadType.DOWNLOAD)
     }
 
     @Suppress("LongParameterList")

+ 71 - 38
app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt

@@ -26,10 +26,13 @@ import android.accounts.AccountManager
 import android.accounts.OnAccountsUpdateListener
 import android.app.PendingIntent
 import android.content.Context
+import androidx.core.util.component1
+import androidx.core.util.component2
 import androidx.localbroadcastmanager.content.LocalBroadcastManager
 import androidx.work.Worker
 import androidx.work.WorkerParameters
 import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
 import com.nextcloud.client.account.User
 import com.nextcloud.client.account.UserAccountManager
 import com.nextcloud.java.util.Optional
@@ -43,6 +46,7 @@ import com.owncloud.android.lib.common.OwnCloudAccount
 import com.owncloud.android.lib.common.OwnCloudClient
 import com.owncloud.android.lib.common.OwnCloudClientManagerFactory
 import com.owncloud.android.lib.common.network.OnDatatransferProgressListener
+import com.owncloud.android.lib.common.operations.OperationCancelledException
 import com.owncloud.android.lib.common.operations.RemoteOperationResult
 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode
 import com.owncloud.android.lib.common.utils.Log_OC
@@ -51,6 +55,7 @@ import com.owncloud.android.operations.DownloadType
 import com.owncloud.android.utils.theme.ViewThemeUtils
 import java.util.AbstractList
 import java.util.Vector
+import java.util.concurrent.atomic.AtomicBoolean
 
 @Suppress("LongParameterList")
 class FileDownloadWorker(
@@ -67,6 +72,7 @@ class FileDownloadWorker(
 
         const val USER_NAME = "USER"
         const val FILE = "FILE"
+        const val FILES = "FILES"
         const val BEHAVIOUR = "BEHAVIOUR"
         const val DOWNLOAD_TYPE = "DOWNLOAD_TYPE"
         const val ACTIVITY_NAME = "ACTIVITY_NAME"
@@ -123,50 +129,47 @@ class FileDownloadWorker(
         }
     }
 
+    override fun onStopped() {
+        setIdleWorkerState()
+        super.onStopped()
+    }
+
     private fun getRequestDownloads(): AbstractList<String> {
+        val files = getFiles()
+        val downloadType = getDownloadType()
+        setUser()
+
         conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long?
-        val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java)
-        val accountName = inputData.keyValueMap[USER_NAME] as String
-        user = accountManager.getUser(accountName).get()
-        val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String?
-        val downloadType = if (downloadTypeAsString != null) {
-            if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) {
-                DownloadType.DOWNLOAD
-            } else {
-                DownloadType.EXPORT
-            }
-        } else {
-            null
-        }
-        val behaviour = inputData.keyValueMap[BEHAVIOUR] as String
-        val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String
-        val packageName = inputData.keyValueMap[PACKAGE_NAME] as String
+        val behaviour = inputData.keyValueMap[BEHAVIOUR] as String? ?: ""
+        val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String? ?: ""
+        val packageName = inputData.keyValueMap[PACKAGE_NAME] as String? ?: ""
 
         val requestedDownloads: AbstractList<String> = Vector()
 
         return try {
-            val operation = DownloadFileOperation(
-                user,
-                file,
-                behaviour,
-                activityName,
-                packageName,
-                context,
-                downloadType
-            )
-
-            operation.addDownloadDataTransferProgressListener(this)
-            operation.addDownloadDataTransferProgressListener(downloadProgressListener)
-            val putResult = pendingDownloads.putIfAbsent(
-                user?.accountName,
-                file.remotePath,
-                operation
-            )
-
-            if (putResult != null) {
-                val downloadKey = putResult.first
-                requestedDownloads.add(downloadKey)
-                localBroadcastManager.sendBroadcast(intents.newDownloadIntent(operation, putResult.second))
+            files.forEach { file ->
+                val operation = DownloadFileOperation(
+                    user,
+                    file,
+                    behaviour,
+                    activityName,
+                    packageName,
+                    context,
+                    downloadType
+                )
+
+                operation.addDownloadDataTransferProgressListener(this)
+                operation.addDownloadDataTransferProgressListener(downloadProgressListener)
+                val (downloadKey, linkedToRemotePath) = pendingDownloads.putIfAbsent(
+                    user?.accountName,
+                    file.remotePath,
+                    operation
+                )
+
+                if (downloadKey != null) {
+                    requestedDownloads.add(downloadKey)
+                    localBroadcastManager.sendBroadcast(intents.newDownloadIntent(operation, linkedToRemotePath))
+                }
             }
 
             requestedDownloads
@@ -176,6 +179,36 @@ class FileDownloadWorker(
         }
     }
 
+    private fun setUser() {
+        val accountName = inputData.keyValueMap[USER_NAME] as String
+        user = accountManager.getUser(accountName).get()
+    }
+
+    private fun getFiles(): List<OCFile> {
+        val filesJson = inputData.keyValueMap[FILES] as String?
+
+        return if (filesJson != null) {
+            val ocFileListType = object : TypeToken<ArrayList<OCFile>>() {}.type
+            gson.fromJson(filesJson, ocFileListType)
+        } else {
+            val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java)
+            listOf(file)
+        }
+    }
+
+    private fun getDownloadType(): DownloadType? {
+        val typeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String?
+        return if (typeAsString != null) {
+            if (typeAsString == DownloadType.DOWNLOAD.toString()) {
+                DownloadType.DOWNLOAD
+            } else {
+                DownloadType.EXPORT
+            }
+        } else {
+            null
+        }
+    }
+
     private fun setWorkerState(user: User?, file: DownloadFileOperation?) {
         WorkerStateLiveData.instance().setWorkState(WorkerState.Download(user, file))
     }

+ 8 - 1
app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt

@@ -24,6 +24,7 @@ import androidx.work.ListenableWorker
 import com.nextcloud.client.account.User
 import com.owncloud.android.datamodel.OCFile
 import com.owncloud.android.operations.DownloadType
+import java.util.concurrent.atomic.AtomicBoolean
 
 /**
  * This interface allows to control, schedule and monitor all application
@@ -152,7 +153,7 @@ interface BackgroundJobManager {
     @Suppress("LongParameterList")
     fun startFileDownloadJob(
         user: User,
-        ocFile: OCFile,
+        file: OCFile,
         behaviour: String,
         downloadType: DownloadType?,
         activityName: String,
@@ -160,6 +161,12 @@ interface BackgroundJobManager {
         conflictUploadId: Long?
     )
 
+    fun startFolderDownloadJob(
+        folder: OCFile,
+        user: User,
+        files: List<OCFile>
+    )
+
     fun startPdfGenerateAndUploadWork(user: User, uploadFolder: String, imagePaths: List<String>, pdfPath: String)
 
     fun scheduleTestJob()

+ 29 - 35
app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt

@@ -47,6 +47,7 @@ import com.owncloud.android.operations.DownloadType
 import java.util.Date
 import java.util.UUID
 import java.util.concurrent.TimeUnit
+import java.util.concurrent.atomic.AtomicBoolean
 import kotlin.reflect.KClass
 
 /**
@@ -108,6 +109,7 @@ internal class BackgroundJobManagerImpl(
         const val PERIODIC_BACKUP_INTERVAL_MINUTES = 24 * 60L
         const val DEFAULT_PERIODIC_JOB_INTERVAL_MINUTES = 15L
         const val DEFAULT_IMMEDIATE_JOB_DELAY_SEC = 3L
+        private val gson = Gson()
 
         private const val KEEP_LOG_MILLIS = 1000 * 60 * 60 * 24 * 3L
 
@@ -510,61 +512,53 @@ internal class BackgroundJobManagerImpl(
         workManager.enqueueUniqueWork(JOB_FILES_UPLOAD + user.accountName, ExistingWorkPolicy.KEEP, request)
     }
 
-    @Suppress("LongParameterList")
-    private fun getOneTimeDownloadRequest(
-        user: User,
-        file: OCFile,
-        behaviour: String,
-        downloadType: DownloadType?,
-        activityName: String,
-        packageName: String,
-        conflictUploadId: Long?
-    ): OneTimeWorkRequest {
-        val gson = Gson()
+    private fun startFileDownloadJobTag(user: User, file: OCFile): String {
+        return JOB_FILES_DOWNLOAD + user.accountName + file.fileId
+    }
 
+    override fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean {
+        return workManager.isWorkScheduled(startFileDownloadJobTag(user, file))
+    }
+
+    override fun startFolderDownloadJob(folder: OCFile, user: User, files: List<OCFile>) {
         val data = workDataOf(
             FileDownloadWorker.USER_NAME to user.accountName,
-            FileDownloadWorker.FILE to gson.toJson(file),
-            FileDownloadWorker.BEHAVIOUR to behaviour,
-            FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(),
-            FileDownloadWorker.ACTIVITY_NAME to activityName,
-            FileDownloadWorker.PACKAGE_NAME to packageName,
-            FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId
+            FileDownloadWorker.FILES to gson.toJson(files),
+            FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString(),
         )
 
-        return oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user)
+        val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user)
             .setInputData(data)
             .build()
-    }
-
-    private fun startFileDownloadJobTag(user: User, file: OCFile): String {
-        return JOB_FILES_DOWNLOAD + user.accountName + file.fileId
-    }
 
-    override fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean {
-        return workManager.isWorkScheduled(startFileDownloadJobTag(user, file))
+        val tag = startFileDownloadJobTag(user, folder)
+        workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request)
     }
 
     override fun startFileDownloadJob(
         user: User,
-        ocFile: OCFile,
+        file: OCFile,
         behaviour: String,
         downloadType: DownloadType?,
         activityName: String,
         packageName: String,
         conflictUploadId: Long?
     ) {
-        val request = getOneTimeDownloadRequest(
-            user,
-            ocFile,
-            behaviour,
-            downloadType,
-            activityName,
-            packageName,
-            conflictUploadId
+        val data = workDataOf(
+            FileDownloadWorker.USER_NAME to user.accountName,
+            FileDownloadWorker.FILE to gson.toJson(file),
+            FileDownloadWorker.BEHAVIOUR to behaviour,
+            FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(),
+            FileDownloadWorker.ACTIVITY_NAME to activityName,
+            FileDownloadWorker.PACKAGE_NAME to packageName,
+            FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId,
         )
 
-        val tag = startFileDownloadJobTag(user, ocFile)
+        val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user)
+            .setInputData(data)
+            .build()
+
+        val tag = startFileDownloadJobTag(user, file)
         workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request)
     }
 

+ 16 - 2
app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java

@@ -44,6 +44,7 @@ import com.owncloud.android.utils.MimeTypeUtil;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Vector;
@@ -438,13 +439,22 @@ public class SynchronizeFolderOperation extends SyncOperation {
         }
     }
 
-
     private void syncContents() throws OperationCancelledException {
         startDirectDownloads();
         startContentSynchronizations(mFilesToSyncContents);
     }
 
-    private void startDirectDownloads() throws OperationCancelledException {
+    public static HashMap<Long, Boolean> folderDownloadStatusPair = new HashMap<>();
+
+    private void startDirectDownloads() {
+        FileDownloadHelper.Companion.instance().downloadFolder(mLocalFolder,
+                                                               user,
+                                                               mFilesForDirectDownload);
+
+        // FIXME cancel request
+        /*
+        folderDownloadStatusPair.put(mLocalFolder.getFileId(), true);
+
         for (OCFile file : mFilesForDirectDownload) {
             synchronized(mCancellationRequested) {
                 if (mCancellationRequested.get()) {
@@ -453,6 +463,10 @@ public class SynchronizeFolderOperation extends SyncOperation {
                 FileDownloadHelper.Companion.instance().downloadFile(user, file);
             }
         }
+
+        folderDownloadStatusPair.replace(mLocalFolder.getFileId(), false);
+         */
+
     }
 
     /**