Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,15 @@ class InternalTwoWaySyncWork(
}

Log_OC.d(TAG, "Folder ${folder.remotePath}: started!")
operation = SynchronizeFolderOperation(context, folder.remotePath, user, fileDataStorageManager, true)
operation =
SynchronizeFolderOperation(
context,
folder.remotePath,
user,
fileDataStorageManager,
true,
false
)
val operationResult = operation?.execute(context)

if (operationResult?.isSuccess == true) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ import com.owncloud.android.lib.common.OwnCloudClientManagerFactory
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.operations.DownloadFileOperation
import com.owncloud.android.operations.DownloadType
import com.owncloud.android.ui.helpers.FileOperationsHelper
import com.owncloud.android.utils.FileStorageUtils
import com.owncloud.android.utils.theme.ViewThemeUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import java.util.concurrent.ConcurrentHashMap

@Suppress("LongMethod", "TooGenericExceptionCaught")
@Suppress("LongMethod", "TooGenericExceptionCaught", "MagicNumber")
class FolderDownloadWorker(
private val accountManager: UserAccountManager,
private val context: Context,
Expand All @@ -39,9 +40,7 @@ class FolderDownloadWorker(
private const val TAG = "📂" + "FolderDownloadWorker"
const val FOLDER_ID = "FOLDER_ID"
const val ACCOUNT_NAME = "ACCOUNT_NAME"

private val pendingDownloads: MutableSet<Long> = ConcurrentHashMap.newKeySet<Long>()

private val pendingDownloads: MutableSet<Long> = ConcurrentHashMap.newKeySet()
fun isDownloading(id: Long): Boolean = pendingDownloads.contains(id)
}

Expand All @@ -58,42 +57,55 @@ class FolderDownloadWorker(

val accountName = inputData.getString(ACCOUNT_NAME)
if (accountName == null) {
Log_OC.e(TAG, "failed accountName cannot be null")
Log_OC.e(TAG, "failed: accountName cannot be null")
return Result.failure()
}

val optionalUser = accountManager.getUser(accountName)
if (optionalUser.isEmpty) {
Log_OC.e(TAG, "failed user is not present")
Log_OC.e(TAG, "failed: user is not present")
return Result.failure()
}

val user = optionalUser.get()
storageManager = FileDataStorageManager(user, context.contentResolver)

val folder = storageManager.getFileById(folderID)
if (folder == null) {
Log_OC.e(TAG, "failed folder cannot be nul")
Log_OC.e(TAG, "failed: folder cannot be null")
return Result.failure()
}

Log_OC.d(TAG, "🕒 started for ${user.accountName} downloading ${folder.fileName}")
Log_OC.d(TAG, "🕒 started for ${user.accountName} | folder=${folder.fileName}")

trySetForeground(folder)

folderDownloadEventBroadcaster.sendDownloadEnqueued(folder.fileId)
pendingDownloads.add(folder.fileId)

val downloadHelper = FileDownloadHelper.instance()

return withContext(Dispatchers.IO) {
try {
val files = getFiles(folder, storageManager)
val account = user.toOwnCloudAccount()
val client = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(account, context)
val client = OwnCloudClientManagerFactory.getDefaultSingleton()
.getClientFor(account, context)
val files = getFiles(folder, storageManager)
if (files.isEmpty()) {
Log_OC.d(TAG, "✅ no files need downloading")
notificationManager.showCompletionNotification(folder.fileName, true)
return@withContext Result.success()
}

var overallSuccess = true

var result = true
files.forEachIndexed { index, file ->
if (!checkDiskSize(file)) {
if (isStopped) {
Log_OC.d(TAG, "⚠️ worker stopped mid-download, aborting remaining files")
return@withContext Result.failure()
}

if (!FileStorageUtils.checkIfEnoughSpace(folder)) {
notificationManager.showNotAvailableDiskSpace()
return@withContext Result.failure()
}

Expand All @@ -105,41 +117,43 @@ class FolderDownloadWorker(
files.size
)
notificationManager.showNotification(notification)

val foregroundInfo = notificationManager.getForegroundInfo(notification)
setForeground(foregroundInfo)
setForeground(notificationManager.getForegroundInfo(notification))
}

val operation = DownloadFileOperation(user, file, context)
val operationResult = operation.execute(client)

if (operationResult?.isSuccess == true && operation.downloadType === DownloadType.DOWNLOAD) {
getOCFile(operation)?.let { ocFile ->
downloadHelper.saveFile(ocFile, operation, storageManager)
}
}

if (!operationResult.isSuccess) {
result = false
if (operationResult?.isSuccess != true) {
Log_OC.w(TAG, "⚠️ download failed for ${file.remotePath}: ${operationResult?.logMessage}")
overallSuccess = false
}
}

withContext(Dispatchers.Main) {
notificationManager.showCompletionNotification(folder.fileName, result)
}
notificationManager.showCompletionNotification(folder.fileName, overallSuccess)

if (result) {
Log_OC.d(TAG, "✅ completed")
if (overallSuccess) {
Log_OC.d(TAG, "✅ completed successfully")
Result.success()
} else {
Log_OC.d(TAG, "❌ failed")
Log_OC.d(TAG, "❌ completed with failures")
Result.failure()
}
} catch (e: Exception) {
Log_OC.d(TAG, "❌ failed reason: $e")
Log_OC.e(TAG, "❌ unexpected failure: $e")
notificationManager.showCompletionNotification(folder.fileName, false)
Result.failure()
} finally {
folderDownloadEventBroadcaster.sendDownloadCompleted(folder.fileId)
pendingDownloads.remove(folder.fileId)

// delay so that user can see the error or success notification
delay(2000)
notificationManager.dismiss()
}
}
Expand All @@ -155,11 +169,12 @@ class FolderDownloadWorker(
return notificationManager.getForegroundInfo(null)
}

val folder = storageManager.getFileById(folderID) ?: return notificationManager.getForegroundInfo(null)
val folder = storageManager.getFileById(folderID)
?: return notificationManager.getForegroundInfo(null)

return notificationManager.getForegroundInfo(folder)
notificationManager.getForegroundInfo(folder)
} catch (e: Exception) {
Log_OC.w(TAG, "⚠️ Error getting foreground info: ${e.message}")
Log_OC.w(TAG, "⚠️ error getting foreground info: ${e.message}")
notificationManager.getForegroundInfo(null)
}
}
Expand All @@ -169,34 +184,20 @@ class FolderDownloadWorker(
val foregroundInfo = notificationManager.getForegroundInfo(folder)
setForeground(foregroundInfo)
} catch (e: Exception) {
Log_OC.w(TAG, "⚠️ Could not set foreground service: ${e.message}")
Log_OC.w(TAG, "⚠️ could not set foreground service: ${e.message}")
}
}

private fun getOCFile(operation: DownloadFileOperation): OCFile? {
val file = operation.file?.fileId?.let { storageManager.getFileById(it) }
?: storageManager.getFileByDecryptedRemotePath(operation.file?.remotePath)
?: run {
Log_OC.e(TAG, "could not save ${operation.file?.remotePath}")
return null
}

return file
private fun getOCFile(operation: DownloadFileOperation): OCFile? = operation.file?.fileId?.let {
storageManager.getFileById(it)
}
?: storageManager.getFileByDecryptedRemotePath(operation.file?.remotePath)
?: run {
Log_OC.e(TAG, "could not resolve OCFile for save: ${operation.file?.remotePath}")
null
}

private fun getFiles(folder: OCFile, storageManager: FileDataStorageManager): List<OCFile> =
storageManager.getFolderContent(folder, false)
.filter { !it.isFolder && !it.isDown }

private fun checkDiskSize(file: OCFile): Boolean {
val fileSizeInByte = file.fileLength
val availableDiskSpace = FileOperationsHelper.getAvailableSpaceOnDevice()

return if (availableDiskSpace < fileSizeInByte) {
notificationManager.showNotAvailableDiskSpace()
false
} else {
true
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import com.owncloud.android.R
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.ui.notifications.NotificationUtils
import com.owncloud.android.utils.theme.ViewThemeUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlin.random.Random

class FolderDownloadWorkerNotificationManager(private val context: Context, viewThemeUtils: ViewThemeUtils) :
Expand Down Expand Up @@ -78,7 +80,7 @@ class FolderDownloadWorkerNotificationManager(private val context: Context, view
return getNotification(folderName, description, progress)
}

fun showCompletionNotification(folderName: String, success: Boolean) {
suspend fun showCompletionNotification(folderName: String, success: Boolean) = withContext(Dispatchers.Main) {
val titleId = if (success) {
R.string.folder_download_success_notification_title
} else {
Expand All @@ -91,10 +93,10 @@ class FolderDownloadWorkerNotificationManager(private val context: Context, view
notificationManager.notify(NOTIFICATION_ID, notification)
}

fun showNotAvailableDiskSpace() {
suspend fun showNotAvailableDiskSpace() = withContext(Dispatchers.Main) {
val title = context.getString(R.string.folder_download_insufficient_disk_space_notification_title)
val notification = getNotification(title)
notificationManager.notify(NOTIFICATION_ID, notification)
notificationManager.notify(Random.nextInt(), notification)
}

fun getForegroundInfo(folder: OCFile?): ForegroundInfo {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,6 @@ class FileUploadHelper {
files: List<OCFile>,
accountName: String
): Pair<List<SyncedFolderEntity>, List<OCFile>> {

val autoUploadFolders = mutableListOf<SyncedFolderEntity>()
val nonAutoUploadFiles = mutableListOf<OCFile>()

Expand Down
48 changes: 32 additions & 16 deletions app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ enum class FileAction(

// Uploads and downloads
DOWNLOAD_FILE(R.id.action_download_file, R.string.filedetails_download, R.drawable.ic_cloud_download),
DOWNLOAD_FOLDER(R.id.action_sync_file, R.string.filedetails_sync_file, R.drawable.ic_sync),
SYNC_FOLDER(R.id.action_sync_file, R.string.filedetails_sync_file, R.drawable.ic_sync),
SYNC_ALL_FOLDERS(R.id.action_sync_all_files, R.string.filedetails_sync_all_files, R.drawable.ic_sync_all),
CANCEL_SYNC(R.id.action_cancel_sync, R.string.common_cancel_sync, R.drawable.ic_sync_off),

// File sharing
Expand Down Expand Up @@ -71,7 +72,7 @@ enum class FileAction(
* All file actions, in the order they should be displayed
*/
fun getActions(files: Collection<OCFile>): List<FileAction> {
return mutableListOf(
val result = mutableListOf(
UNLOCK_FILE,
EDIT,
FAVORITE,
Expand All @@ -86,19 +87,31 @@ enum class FileAction(
SEND_SHARE_FILE,
SEND_FILE,
OPEN_FILE_WITH,
DOWNLOAD_FOLDER,
CANCEL_SYNC,
SELECT_ALL,
SELECT_NONE,
SET_ENCRYPTED,
UNSET_ENCRYPTED,
SET_AS_WALLPAPER,
PIN_TO_HOMESCREEN,
RETRY
).apply {
val deleteOrLeaveShareAction = getDeleteOrLeaveShareAction(files) ?: return@apply
add(deleteOrLeaveShareAction)
SYNC_FOLDER
)

if (files.size == 1 && files.first().isFolder && !files.first().isEncrypted) {
result.add(SYNC_ALL_FOLDERS)
}

result.addAll(
listOf(
CANCEL_SYNC,
SELECT_ALL,
SELECT_NONE,
SET_ENCRYPTED,
UNSET_ENCRYPTED,
SET_AS_WALLPAPER,
PIN_TO_HOMESCREEN,
RETRY
)
)

getDeleteOrLeaveShareAction(files)?.let {
result.add(it)
}

return result
}

fun getFilePreviewActions(file: OCFile?): List<Int> {
Expand All @@ -113,7 +126,7 @@ enum class FileAction(

if (file != null) {
val actionsToHide = getActionsToHide(setOf(file))
result.removeAll(actionsToHide)
result.removeAll(actionsToHide.toSet())
}

return result.toList()
Expand All @@ -136,6 +149,7 @@ enum class FileAction(
if (file?.isFolder == true) {
result.add(R.id.action_send_file)
result.add(R.id.action_sync_file)
result.add(R.id.action_sync_all_files)
}

if (file?.isAPKorAAB == true) {
Expand All @@ -145,7 +159,7 @@ enum class FileAction(

if (file != null) {
val actionsToHide = getActionsToHide(setOf(file))
result.removeAll(actionsToHide)
result.removeAll(actionsToHide.toSet())
}

return result.toList()
Expand All @@ -160,6 +174,7 @@ enum class FileAction(
R.id.action_favorite,
R.id.action_move_or_copy,
R.id.action_sync_file,
R.id.action_sync_all_files,
R.id.action_encrypted,
R.id.action_unset_encrypted,
R.id.action_edit,
Expand All @@ -176,6 +191,7 @@ enum class FileAction(
R.id.action_send_share_file,
R.id.action_export_file,
R.id.action_sync_file,
R.id.action_sync_all_files,
R.id.action_download_file
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ private void filterSync(List<Integer> toHide, boolean synchronizing) {
if (files.isEmpty() || (!anyFileDown() && !containsFolder()) || synchronizing || containsEncryptedFile()
|| containsEncryptedFolder()) {
toHide.add(R.id.action_sync_file);
toHide.add(R.id.action_sync_all_files);
}
}

Expand Down
Loading
Loading