diff --git a/owncloudApp/src/main/java/com/owncloud/android/datamodel/OCUpload.java b/owncloudApp/src/main/java/com/owncloud/android/datamodel/OCUpload.java index 3d7424ee60b..720cade22db 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/datamodel/OCUpload.java +++ b/owncloudApp/src/main/java/com/owncloud/android/datamodel/OCUpload.java @@ -32,7 +32,7 @@ import com.owncloud.android.db.UploadResult; import com.owncloud.android.domain.camerauploads.model.UploadBehavior; import com.owncloud.android.domain.files.model.OCFile; -import com.owncloud.android.usecases.transfers.uploads.UploadEnqueuedBy; +import com.owncloud.android.domain.transfers.model.UploadEnqueuedBy; import com.owncloud.android.utils.MimetypeIconUtil; import timber.log.Timber; diff --git a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/UseCaseModule.kt b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/UseCaseModule.kt index d465d079b94..714cce3e6ea 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/UseCaseModule.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/UseCaseModule.kt @@ -73,6 +73,7 @@ import com.owncloud.android.domain.transfers.usecases.ClearFailedTransfersUseCas import com.owncloud.android.domain.transfers.usecases.ClearSuccessfulTransfersUseCase import com.owncloud.android.domain.transfers.usecases.DeleteTransferWithIdUseCase import com.owncloud.android.domain.transfers.usecases.GetAllTransfersAsLiveDataUseCase +import com.owncloud.android.domain.transfers.usecases.UpdatePendingUploadsPathUseCase import com.owncloud.android.domain.user.usecases.GetStoredQuotaUseCase import com.owncloud.android.domain.user.usecases.GetUserAvatarAsyncUseCase import com.owncloud.android.domain.user.usecases.GetUserInfoAsyncUseCase @@ -172,6 +173,7 @@ val useCaseModule = module { factory { RetryFailedUploadsUseCase(get(), get(), get(), get()) } factory { ClearSuccessfulTransfersUseCase(get()) } factory { CancelUploadsFromAccountUseCase(get(), get()) } + factory { UpdatePendingUploadsPathUseCase(get()) } // User factory { GetStoredQuotaUseCase(get()) } diff --git a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/ViewModelModule.kt b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/ViewModelModule.kt index 4b67de26da4..f3c1ae1d369 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/ViewModelModule.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/dependecyinjection/ViewModelModule.kt @@ -80,7 +80,7 @@ val viewModelModule = module { viewModel { SettingsAdvancedViewModel(get()) } viewModel { RemoveAccountDialogViewModel(get(), get(), get(), get()) } viewModel { LogListViewModel(get()) } - viewModel { MigrationViewModel(MainApp.dataFolder, get(), get(), get(), get(), get(), get()) } + viewModel { MigrationViewModel(MainApp.dataFolder, get(), get(), get(), get(), get(), get(), get()) } viewModel { PatternViewModel(get()) } viewModel { BiometricViewModel(get(), get()) } viewModel { ReleaseNotesViewModel(get(), get()) } diff --git a/owncloudApp/src/main/java/com/owncloud/android/extensions/OCTransferExt.kt b/owncloudApp/src/main/java/com/owncloud/android/extensions/OCTransferExt.kt index d54a936f483..fddc32b78c0 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/extensions/OCTransferExt.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/extensions/OCTransferExt.kt @@ -20,7 +20,10 @@ package com.owncloud.android.extensions +import android.content.Context +import android.net.Uri import androidx.annotation.StringRes +import androidx.documentfile.provider.DocumentFile import com.owncloud.android.R import com.owncloud.android.domain.transfers.model.OCTransfer import com.owncloud.android.domain.transfers.model.TransferResult @@ -61,3 +64,7 @@ fun OCTransfer.statusToStringRes(): Int { } } } + +fun OCTransfer.isContentUri(context: Context): Boolean { + return DocumentFile.isDocumentUri(context, Uri.parse(localPath)) +} diff --git a/owncloudApp/src/main/java/com/owncloud/android/extensions/WorkManagerExt.kt b/owncloudApp/src/main/java/com/owncloud/android/extensions/WorkManagerExt.kt index 6e1657484ed..fa7ab3d9915 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/extensions/WorkManagerExt.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/extensions/WorkManagerExt.kt @@ -28,7 +28,6 @@ import androidx.work.WorkManager import androidx.work.WorkQuery import com.owncloud.android.domain.files.model.OCFile import com.owncloud.android.usecases.transfers.TRANSFER_TAG_DOWNLOAD -import com.owncloud.android.workers.UploadFileFromContentUriWorker.Companion.TRANSFER_TAG_MANUAL_UPLOAD val PENDING_WORK_STATUS = listOf(WorkInfo.State.ENQUEUED, WorkInfo.State.RUNNING, WorkInfo.State.BLOCKED) val FINISHED_WORK_STATUS = listOf(WorkInfo.State.SUCCEEDED, WorkInfo.State.FAILED, WorkInfo.State.CANCELLED) @@ -70,9 +69,6 @@ fun WorkManager.isUploadPending(account: Account, file: OCFile): Boolean = false fun getTagsForDownload(file: OCFile, accountName: String) = listOf(TRANSFER_TAG_DOWNLOAD, file.id.toString(), accountName) -fun getTagsForUpload(file: OCFile, account: Account) = - listOf(TRANSFER_TAG_MANUAL_UPLOAD, file.id.toString(), account.name) - /** * Take care with WorkQueries. It will return workers that match at least ONE of the tags. * If we perform a query with tags {"account@server", "2"}, [WorkManager.getWorkInfos] will return workers that diff --git a/owncloudApp/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/owncloudApp/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index c06cbf123a3..ae827735fdc 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/owncloudApp/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -30,8 +30,6 @@ import androidx.annotation.NonNull; import androidx.core.util.Pair; import com.owncloud.android.datamodel.FileDataStorageManager; -import com.owncloud.android.datamodel.OCUpload; -import com.owncloud.android.datamodel.UploadsStorageManager; import com.owncloud.android.domain.UseCaseResult; import com.owncloud.android.domain.availableoffline.model.AvailableOfflineStatus; import com.owncloud.android.domain.files.model.OCFile; @@ -61,7 +59,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import static com.owncloud.android.usecases.synchronization.SynchronizeFolderUseCase.SyncFolderMode.REFRESH_FOLDER; -import static com.owncloud.android.usecases.synchronization.SynchronizeFolderUseCase.SyncFolderMode.SYNC_FOLDER_RECURSIVELY; import static org.koin.java.KoinJavaComponent.get; import static org.koin.java.KoinJavaComponent.inject; @@ -447,7 +444,9 @@ private boolean addToSyncContents(OCFile localFile, OCFile remoteFile) { // files do not use treeEtag serverUnchanged = (remoteFile == null) || localFile.getEtag().equals(remoteFile.getEtag()); - if (shouldSyncContents && !isBlockedForAutomatedSync(localFile)) { + // TODO: check if necessary + // if (shouldSyncContents && !isBlockedForAutomatedSync(localFile)) { + if (shouldSyncContents) { /// synchronization for files mFilesToSyncContents.add(localFile); } @@ -545,6 +544,7 @@ public String getFolderPath() { * @return 'True' if the received file should not be automatically synced due to a previous * upload error that requires an user action. */ + /* private boolean isBlockedForAutomatedSync(OCFile file) { UploadsStorageManager uploadsStorageManager = new UploadsStorageManager(mContext.getContentResolver()); OCUpload failedUpload = uploadsStorageManager.getLastUploadFor(file, mAccount.name); @@ -561,6 +561,7 @@ private boolean isBlockedForAutomatedSync(OCFile file) { } return false; } + */ public String getRemotePath() { return mRemotePath; diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/viewmodels/migration/MigrationViewModel.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/viewmodels/migration/MigrationViewModel.kt index 88dd9c98243..2e9e406661c 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/viewmodels/migration/MigrationViewModel.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/viewmodels/migration/MigrationViewModel.kt @@ -3,7 +3,9 @@ * * @author David González Verdugo * @author Abel García de Prada - * Copyright (C) 2020 ownCloud GmbH. + * @author Juan Carlos Garrote Gascón + * + * Copyright (C) 2022 ownCloud GmbH. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -30,15 +32,14 @@ import com.owncloud.android.data.preferences.datasources.SharedPreferencesProvid import com.owncloud.android.data.storage.LegacyStorageProvider import com.owncloud.android.data.storage.LocalStorageProvider import com.owncloud.android.datamodel.FileDataStorageManager -import com.owncloud.android.datamodel.OCUpload -import com.owncloud.android.datamodel.UploadsStorageManager +import com.owncloud.android.domain.transfers.usecases.GetAllTransfersUseCase +import com.owncloud.android.domain.transfers.usecases.UpdatePendingUploadsPathUseCase import com.owncloud.android.domain.utils.Event import com.owncloud.android.presentation.ui.migration.StorageMigrationActivity.Companion.PREFERENCE_ALREADY_MIGRATED_TO_SCOPED_STORAGE import com.owncloud.android.providers.AccountProvider import com.owncloud.android.providers.ContextProvider import com.owncloud.android.providers.CoroutinesDispatcherProvider import kotlinx.coroutines.launch -import timber.log.Timber import java.io.File /** @@ -48,9 +49,10 @@ class MigrationViewModel( rootFolder: String, private val localStorageProvider: LocalStorageProvider, private val preferencesProvider: SharedPreferencesProvider, - private val uploadsStorageManager: UploadsStorageManager, private val contextProvider: ContextProvider, private val accountProvider: AccountProvider, + private val updatePendingUploadsPathUseCase: UpdatePendingUploadsPathUseCase, + private val getAllTransfersUseCase: GetAllTransfersUseCase, private val coroutineDispatcherProvider: CoroutinesDispatcherProvider, ) : ViewModel() { @@ -82,43 +84,18 @@ class MigrationViewModel( } private fun updatePendingUploadsPath() { - uploadsStorageManager.clearSuccessfulUploads() - val storedUploads: Array = uploadsStorageManager.allStoredUploads - val uploadsWithUpdatedPath = - storedUploads.map { - it.apply { localPath = localPath.replace(legacyStorageDirectoryPath, localStorageProvider.getRootFolderPath()) } - } - uploadsWithUpdatedPath.forEach { uploadsStorageManager.updateUpload(it) } - clearUnrelatedTemporalFiles(uploadsWithUpdatedPath) - } - - private fun clearUnrelatedTemporalFiles(pendingUploads: List) { - val listOfAccounts = accountProvider.getLoggedAccounts() - - listOfAccounts.forEach { account -> - val temporalFolderForAccount = File(localStorageProvider.getTemporalPath(account.name)) - - cleanTemporalRecursively(temporalFolderForAccount) { temporalFile -> - if (!pendingUploads.map { it.localPath }.contains(temporalFile.absolutePath)) { - Timber.d("Found a temporary file that is not needed: $temporalFile, so let's delete it") - temporalFile.delete() - } - } - } - } - - private fun cleanTemporalRecursively( - temporalFolder: File, - deleteFileInCaseItIsNotNeeded: (file: File) -> Unit - ) { - temporalFolder.listFiles()?.forEach { temporalFile -> - if (temporalFile.isDirectory) { - cleanTemporalRecursively(temporalFile, deleteFileInCaseItIsNotNeeded) - } else { - deleteFileInCaseItIsNotNeeded(temporalFile) - } - + updatePendingUploadsPathUseCase.execute( + UpdatePendingUploadsPathUseCase.Params( + oldDirectory = legacyStorageDirectoryPath, + newDirectory = localStorageProvider.getRootFolderPath() + ) + ) + val uploads = getAllTransfersUseCase.execute(Unit) + val accountsNames = mutableListOf() + accountProvider.getLoggedAccounts().forEach { account -> + accountsNames.add(localStorageProvider.getTemporalPath(account.name)) } + localStorageProvider.clearUnrelatedTemporalFiles(uploads, accountsNames) } private fun updateAlreadyDownloadedFilesPath() { diff --git a/owncloudApp/src/main/java/com/owncloud/android/providers/FileContentProvider.kt b/owncloudApp/src/main/java/com/owncloud/android/providers/FileContentProvider.kt index 9ab33857826..df01680f1a0 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/providers/FileContentProvider.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/providers/FileContentProvider.kt @@ -7,8 +7,10 @@ * @author David González Verdugo * @author Christian Schabesberger * @author Abel García de Prada + * @author Juan Carlos Garrote Gascón + * * Copyright (C) 2011 Bartek Przybylski - * Copyright (C) 2020 ownCloud GmbH. + * Copyright (C) 2022 ownCloud GmbH. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -60,17 +62,21 @@ import com.owncloud.android.data.folderbackup.datasources.FolderBackupLocalDataS import com.owncloud.android.data.migrations.CameraUploadsMigrationToRoom import com.owncloud.android.data.preferences.datasources.SharedPreferencesProvider import com.owncloud.android.data.sharing.shares.db.OCShareEntity -import com.owncloud.android.datamodel.UploadsStorageManager +import com.owncloud.android.data.transfers.db.OCTransferEntity +import com.owncloud.android.data.transfers.db.TransferDao import com.owncloud.android.db.ProviderMeta.ProviderTableMeta +import com.owncloud.android.domain.camerauploads.model.UploadBehavior +import com.owncloud.android.domain.files.model.LIST_MIME_DIR +import com.owncloud.android.domain.transfers.model.TransferStatus import com.owncloud.android.extensions.getLongFromColumnOrThrow import com.owncloud.android.extensions.getStringFromColumnOrThrow -import com.owncloud.android.domain.files.model.LIST_MIME_DIR import com.owncloud.android.lib.common.accounts.AccountUtils +import com.owncloud.android.domain.transfers.model.UploadEnqueuedBy +import com.owncloud.android.usecases.transfers.uploads.UploadFileFromSystemUseCase import org.koin.android.ext.android.inject import timber.log.Timber +import java.io.File import java.io.FileNotFoundException -import java.util.ArrayList -import java.util.HashMap /** * The ContentProvider for the ownCloud App. @@ -537,6 +543,7 @@ class FileContentProvider(val executors: Executors = Executors()) : ContentProvi override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { Timber.i("SQL : Entering in onUpgrade") var upgraded = false + if (oldVersion == 1 && newVersion >= 2) { Timber.i("SQL : Entering in the #1 ADD in onUpgrade") db.execSQL( @@ -546,6 +553,7 @@ class FileContentProvider(val executors: Executors = Executors()) : ContentProvi ) upgraded = true } + if (oldVersion < 3 && newVersion >= 3) { Timber.i("SQL : Entering in the #2 ADD in onUpgrade") db.beginTransaction() @@ -568,6 +576,7 @@ class FileContentProvider(val executors: Executors = Executors()) : ContentProvi db.endTransaction() } } + if (oldVersion < 4 && newVersion >= 4) { Timber.i("SQL : Entering in the #3 ADD in onUpgrade") db.beginTransaction() @@ -774,6 +783,7 @@ class FileContentProvider(val executors: Executors = Executors()) : ContentProvi db.endTransaction() } } + if (oldVersion < 17 && newVersion >= 17) { Timber.i("SQL : Entering in the #17 ADD in onUpgrade") db.beginTransaction() @@ -791,6 +801,7 @@ class FileContentProvider(val executors: Executors = Executors()) : ContentProvi db.endTransaction() } } + if (oldVersion < 18 && newVersion >= 18) { Timber.i("SQL : Entering in the #18 ADD in onUpgrade") db.beginTransaction() @@ -806,6 +817,7 @@ class FileContentProvider(val executors: Executors = Executors()) : ContentProvi db.endTransaction() } } + if (oldVersion < 19 && newVersion >= 19) { Timber.i("SQL : Entering in the #19 ADD in onUpgrade") @@ -822,6 +834,7 @@ class FileContentProvider(val executors: Executors = Executors()) : ContentProvi db.endTransaction() } } + if (oldVersion < 20 && newVersion >= 20) { Timber.i("SQL : Entering in the #20 ADD in onUpgrade") @@ -1038,36 +1051,92 @@ class FileContentProvider(val executors: Executors = Executors()) : ContentProvi } if (oldVersion < 37 && newVersion >= 37) { - Timber.i("SQL : Entering in #37 to migrate ocfiles from SQLite to Room") - val cursor = db.query( - ProviderTableMeta.FILE_TABLE_NAME, - null, - null, - null, - null, - null, - null - ) + Timber.i("SQL : Entering in #37 to migrate files and uploads from SQLite to Room") + db.beginTransaction() - if (cursor.moveToFirst()) { - val files = mutableListOf() + try { + val cursorFiles = db.query( + ProviderTableMeta.FILE_TABLE_NAME, + null, + null, + null, + null, + null, + null + ) - do { - files.add(OCFileEntity.fromCursor(cursor)) - } while (cursor.moveToNext()) + if (cursorFiles.moveToFirst()) { + val files = mutableListOf() - // Insert file list to the new files table in new database - val ocFileDao: FileDao by inject() - executors.diskIO().execute { - for (file in files) { - ocFileDao.mergeRemoteAndLocalFile(file) + do { + files.add(OCFileEntity.fromCursor(cursorFiles)) + } while (cursorFiles.moveToNext()) + + // Insert file list to the new files table in new database + val ocFileDao: FileDao by inject() + executors.diskIO().execute { + for (file in files) { + ocFileDao.mergeRemoteAndLocalFile(file) + } } } // Drop old files table from old database db.execSQL("DROP TABLE IF EXISTS " + ProviderTableMeta.FILE_TABLE_NAME + ";") + + val cursorUploads = db.query( + ProviderTableMeta.UPLOADS_TABLE_NAME, + null, + null, + null, + null, + null, + null + ) + + if (cursorUploads.moveToFirst()) { + val uploads = mutableListOf() + + do { + val upload = OCTransferEntity.fromCursor(cursorUploads) + uploads.add(upload) + } while (cursorUploads.moveToNext()) + + // Insert uploads list to the new transfers table in new database + val ocTransferDao: TransferDao by inject() + executors.diskIO().execute { + for (upload in uploads) { + ocTransferDao.insert(upload) + if (upload.status == TransferStatus.TRANSFER_QUEUED.value && + upload.createdBy != UploadEnqueuedBy.ENQUEUED_AS_CAMERA_UPLOAD_PICTURE.ordinal && + upload.createdBy != UploadEnqueuedBy.ENQUEUED_AS_CAMERA_UPLOAD_VIDEO.ordinal + ) { + val localFile = File(upload.localPath) + val uploadFileFromSystemUseCase: UploadFileFromSystemUseCase by inject() + uploadFileFromSystemUseCase.execute( + UploadFileFromSystemUseCase.Params( + accountName = upload.accountName, + localPath = upload.localPath, + lastModifiedInSeconds = localFile.lastModified().div(1_000).toString(), + behavior = UploadBehavior.MOVE.toString(), + uploadPath = upload.remotePath, + uploadIdInStorageManager = upload.id + ) + ) + } + } + } + } + + // Drop old uploads table from old database + db.execSQL("DROP TABLE IF EXISTS " + ProviderTableMeta.UPLOADS_TABLE_NAME + ";") + db.setTransactionSuccessful() + upgraded = true + } finally { + db.endTransaction() } } + if (!upgraded) { Timber.i("SQL : OUT of the ADD in onUpgrade; oldVersion == $oldVersion, newVersion == $newVersion") } @@ -1362,12 +1431,12 @@ class FileContentProvider(val executors: Executors = Executors()) : ContentProvi c = db.rawQuery( "delete from " + ProviderTableMeta.UPLOADS_TABLE_NAME + " where " + ProviderTableMeta.UPLOADS_STATUS + " == " + - UploadsStorageManager.UploadStatus.UPLOAD_SUCCEEDED.value + + LEGACY_UPLOAD_STATUS_SUCCEEDED_VALUE + " and " + ProviderTableMeta._ID + " not in (select " + ProviderTableMeta._ID + " from " + ProviderTableMeta.UPLOADS_TABLE_NAME + " where " + ProviderTableMeta.UPLOADS_STATUS + " == " + - UploadsStorageManager.UploadStatus.UPLOAD_SUCCEEDED.value + + LEGACY_UPLOAD_STATUS_SUCCEEDED_VALUE + " order by " + ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP + " desc limit " + MAX_SUCCESSFUL_UPLOADS + ")", null @@ -1395,6 +1464,8 @@ class FileContentProvider(val executors: Executors = Executors()) : ContentProvi private const val MAX_SUCCESSFUL_UPLOADS = "30" + private const val LEGACY_UPLOAD_STATUS_SUCCEEDED_VALUE = 2 + private val fileProjectionMap = HashMap() init { diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java index 625d50287e6..9ed4a312403 100755 --- a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java +++ b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java @@ -36,7 +36,6 @@ import com.owncloud.android.R; import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.datamodel.OCUpload; -import com.owncloud.android.datamodel.UploadsStorageManager; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.operations.CheckCurrentCredentialsOperation; @@ -53,9 +52,8 @@ import static org.koin.java.KoinJavaComponent.inject; /** - * Activity listing pending, active, and completed uploads. User can delete - * completed uploads from view. Content of this list of coming from - * {@link UploadsStorageManager}. + * Activity listing pending, active, failed and completed uploads. User can delete + * completed and failed uploads from view. */ public class UploadListActivity extends FileActivity implements UploadListFragment.ContainerActivity { diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/CancelUploadForFileUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/CancelUploadForFileUseCase.kt index c6753ec3383..55edb3ec9be 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/CancelUploadForFileUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/CancelUploadForFileUseCase.kt @@ -26,7 +26,6 @@ import com.owncloud.android.domain.BaseUseCase import com.owncloud.android.domain.files.model.OCFile import com.owncloud.android.domain.transfers.TransferRepository import com.owncloud.android.extensions.getWorkInfoByTags -import com.owncloud.android.workers.UploadFileFromContentUriWorker.Companion.TRANSFER_TAG_MANUAL_UPLOAD import timber.log.Timber /** @@ -53,7 +52,7 @@ class CancelUploadForFileUseCase( } val workersToCancel = - workManager.getWorkInfoByTags(listOf(TRANSFER_TAG_MANUAL_UPLOAD, uploadForFile.id.toString(), file.owner)) + workManager.getWorkInfoByTags(listOf(uploadForFile.id.toString(), file.owner)) workersToCancel.forEach { // TODO: We need to check if the work is cancelled before finishing. diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryFailedUploadsUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryFailedUploadsUseCase.kt index 5d140efcb90..e0b14658b20 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryFailedUploadsUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryFailedUploadsUseCase.kt @@ -22,11 +22,9 @@ package com.owncloud.android.usecases.transfers.uploads import android.content.Context -import android.net.Uri -import androidx.documentfile.provider.DocumentFile import com.owncloud.android.domain.BaseUseCase import com.owncloud.android.domain.transfers.TransferRepository -import com.owncloud.android.domain.transfers.model.OCTransfer +import com.owncloud.android.extensions.isContentUri import timber.log.Timber class RetryFailedUploadsUseCase( @@ -44,16 +42,11 @@ class RetryFailedUploadsUseCase( return } failedUploads.forEach { upload -> - if (isContentUri(context = context, upload = upload)) { + if (upload.isContentUri(context)) { retryUploadFromContentUriUseCase.execute(RetryUploadFromContentUriUseCase.Params(upload.id!!)) } else { retryUploadFromSystemUseCase.execute(RetryUploadFromSystemUseCase.Params(upload.id!!)) } } } - - private fun isContentUri(context: Context, upload: OCTransfer): Boolean { - return DocumentFile.isDocumentUri(context, Uri.parse(upload.localPath)) - } - } diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryUploadFromContentUriUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryUploadFromContentUriUseCase.kt index 347f12734fd..9297c380c4a 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryUploadFromContentUriUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryUploadFromContentUriUseCase.kt @@ -25,7 +25,6 @@ import androidx.core.net.toUri import androidx.work.WorkInfo import androidx.work.WorkManager import com.owncloud.android.domain.BaseUseCase -import com.owncloud.android.domain.camerauploads.model.UploadBehavior import com.owncloud.android.domain.transfers.TransferRepository import com.owncloud.android.extensions.getWorkInfoByTags import com.owncloud.android.workers.UploadFileFromContentUriWorker @@ -57,7 +56,7 @@ class RetryUploadFromContentUriUseCase( accountName = uploadToRetry.accountName, contentUri = uploadToRetry.localPath.toUri(), lastModifiedInSeconds = (uploadToRetry.transferEndTimestamp?.div(1000)).toString(), - behavior = UploadBehavior.fromLegacyLocalBehavior(uploadToRetry.localBehaviour).name, + behavior = uploadToRetry.localBehaviour.name, uploadPath = uploadToRetry.remotePath, uploadIdInStorageManager = params.uploadIdInStorageManager, wifiOnly = false, diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryUploadFromSystemUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryUploadFromSystemUseCase.kt index 88328876c2f..aa754d32c16 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryUploadFromSystemUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryUploadFromSystemUseCase.kt @@ -24,7 +24,6 @@ package com.owncloud.android.usecases.transfers.uploads import androidx.work.WorkInfo import androidx.work.WorkManager import com.owncloud.android.domain.BaseUseCase -import com.owncloud.android.domain.camerauploads.model.UploadBehavior import com.owncloud.android.domain.transfers.TransferRepository import com.owncloud.android.extensions.getWorkInfoByTags import com.owncloud.android.workers.UploadFileFromFileSystemWorker @@ -56,7 +55,7 @@ class RetryUploadFromSystemUseCase( accountName = uploadToRetry.accountName, localPath = uploadToRetry.localPath, lastModifiedInSeconds = (uploadToRetry.transferEndTimestamp?.div(1000)).toString(), - behavior = UploadBehavior.fromLegacyLocalBehavior(uploadToRetry.localBehaviour).name, + behavior = uploadToRetry.localBehaviour.name, uploadPath = uploadToRetry.remotePath, uploadIdInStorageManager = params.uploadIdInStorageManager ) diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt index 9c2f39d0bc7..3d27c62a756 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt @@ -56,7 +56,6 @@ class UploadFileFromContentUriUseCase( .setConstraints(constraints) .addTag(params.accountName) .addTag(params.uploadIdInStorageManager.toString()) - .addTag(params.transferTag) .build() workManager.enqueue(uploadFileFromContentUriWorker) @@ -72,6 +71,5 @@ class UploadFileFromContentUriUseCase( val uploadIdInStorageManager: Long, val wifiOnly: Boolean, val chargingOnly: Boolean, - val transferTag: String = UploadFileFromContentUriWorker.TRANSFER_TAG_CAMERA_UPLOAD, ) } diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileInConflictUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileInConflictUseCase.kt index 1503528270f..44c2daed14e 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileInConflictUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileInConflictUseCase.kt @@ -31,6 +31,7 @@ import com.owncloud.android.domain.camerauploads.model.UploadBehavior import com.owncloud.android.domain.transfers.TransferRepository import com.owncloud.android.domain.transfers.model.OCTransfer import com.owncloud.android.domain.transfers.model.TransferStatus +import com.owncloud.android.domain.transfers.model.UploadEnqueuedBy import com.owncloud.android.workers.UploadFileFromFileSystemWorker import timber.log.Timber import java.io.File @@ -83,9 +84,9 @@ class UploadFileInConflictUseCase( accountName = accountName, fileSize = localFile.length(), status = TransferStatus.TRANSFER_QUEUED, - localBehaviour = UploadBehavior.COPY.ordinal, + localBehaviour = UploadBehavior.COPY, forceOverwrite = true, - createdBy = UploadEnqueuedBy.ENQUEUED_BY_USER.ordinal + createdBy = UploadEnqueuedBy.ENQUEUED_BY_USER ) return transferRepository.storeTransfer(ocTransfer).also { diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFilesFromContentUriUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFilesFromContentUriUseCase.kt index 42234549956..e80941bb03e 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFilesFromContentUriUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFilesFromContentUriUseCase.kt @@ -29,6 +29,7 @@ import com.owncloud.android.domain.camerauploads.model.UploadBehavior import com.owncloud.android.domain.transfers.TransferRepository import com.owncloud.android.domain.transfers.model.OCTransfer import com.owncloud.android.domain.transfers.model.TransferStatus +import com.owncloud.android.domain.transfers.model.UploadEnqueuedBy import timber.log.Timber import java.io.File @@ -80,9 +81,9 @@ class UploadFilesFromContentUriUseCase( accountName = accountName, fileSize = documentFile.length(), status = TransferStatus.TRANSFER_QUEUED, - localBehaviour = UploadBehavior.COPY.ordinal, + localBehaviour = UploadBehavior.COPY, forceOverwrite = false, - createdBy = UploadEnqueuedBy.ENQUEUED_BY_USER.ordinal + createdBy = UploadEnqueuedBy.ENQUEUED_BY_USER ) return transferRepository.storeTransfer(ocTransfer).also { @@ -105,8 +106,7 @@ class UploadFilesFromContentUriUseCase( accountName = accountName, uploadIdInStorageManager = uploadIdInStorageManager, wifiOnly = false, - chargingOnly = false, - transferTag = UploadEnqueuedBy.ENQUEUED_BY_USER.toTransferTag() + chargingOnly = false ) uploadFileFromContentUriUseCase.execute(uploadFileParams) } diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFilesFromSystemUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFilesFromSystemUseCase.kt index c8fa0abbfbf..fc3f61b2386 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFilesFromSystemUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFilesFromSystemUseCase.kt @@ -26,6 +26,7 @@ import com.owncloud.android.domain.camerauploads.model.UploadBehavior import com.owncloud.android.domain.transfers.TransferRepository import com.owncloud.android.domain.transfers.model.OCTransfer import com.owncloud.android.domain.transfers.model.TransferStatus +import com.owncloud.android.domain.transfers.model.UploadEnqueuedBy import timber.log.Timber import java.io.File @@ -82,9 +83,9 @@ class UploadFilesFromSystemUseCase( accountName = accountName, fileSize = localFile.length(), status = TransferStatus.TRANSFER_QUEUED, - localBehaviour = UploadBehavior.MOVE.ordinal, + localBehaviour = UploadBehavior.MOVE, forceOverwrite = false, - createdBy = UploadEnqueuedBy.ENQUEUED_BY_USER.ordinal + createdBy = UploadEnqueuedBy.ENQUEUED_BY_USER ) return transferRepository.storeTransfer(ocTransfer).also { diff --git a/owncloudApp/src/main/java/com/owncloud/android/workers/CameraUploadsWorker.kt b/owncloudApp/src/main/java/com/owncloud/android/workers/CameraUploadsWorker.kt index d034326e9c5..e4713d6dec3 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/workers/CameraUploadsWorker.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/workers/CameraUploadsWorker.kt @@ -39,7 +39,7 @@ import com.owncloud.android.domain.transfers.TransferRepository import com.owncloud.android.domain.transfers.model.OCTransfer import com.owncloud.android.domain.transfers.model.TransferStatus import com.owncloud.android.presentation.ui.settings.SettingsActivity -import com.owncloud.android.usecases.transfers.uploads.UploadEnqueuedBy +import com.owncloud.android.domain.transfers.model.UploadEnqueuedBy import com.owncloud.android.usecases.transfers.uploads.UploadFileFromContentUriUseCase import com.owncloud.android.utils.MimetypeIconUtil import com.owncloud.android.utils.NotificationUtils @@ -147,8 +147,8 @@ class CameraUploadsWorker( accountName = folderBackUpConfiguration.accountName, behavior = folderBackUpConfiguration.behavior, createdByWorker = when (syncType) { - SyncType.PICTURE_UPLOADS -> UploadEnqueuedBy.ENQUEUED_AS_CAMERA_UPLOAD_PICTURE.ordinal - SyncType.VIDEO_UPLOADS -> UploadEnqueuedBy.ENQUEUED_AS_CAMERA_UPLOAD_VIDEO.ordinal + SyncType.PICTURE_UPLOADS -> UploadEnqueuedBy.ENQUEUED_AS_CAMERA_UPLOAD_PICTURE + SyncType.VIDEO_UPLOADS -> UploadEnqueuedBy.ENQUEUED_AS_CAMERA_UPLOAD_VIDEO } ) enqueueSingleUpload( @@ -288,7 +288,7 @@ class CameraUploadsWorker( uploadPath: String, accountName: String, behavior: UploadBehavior, - createdByWorker: Int + createdByWorker: UploadEnqueuedBy ): Long { val ocTransfer = OCTransfer( localPath = documentFile.uri.toString(), @@ -296,7 +296,7 @@ class CameraUploadsWorker( accountName = accountName, fileSize = documentFile.length(), status = TransferStatus.TRANSFER_QUEUED, - localBehaviour = behavior.toLegacyLocalBehavior(), + localBehaviour = behavior, forceOverwrite = false, createdBy = createdByWorker ) diff --git a/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromContentUriWorker.kt b/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromContentUriWorker.kt index 849cd3ad199..378e37a7eb5 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromContentUriWorker.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromContentUriWorker.kt @@ -240,9 +240,6 @@ class UploadFileFromContentUriWorker( } companion object { - const val TRANSFER_TAG_CAMERA_UPLOAD = "TRANSFER_TAG_CAMERA_UPLOAD" - const val TRANSFER_TAG_MANUAL_UPLOAD = "TRANSFER_TAG_MANUAL_UPLOAD" - const val KEY_PARAM_ACCOUNT_NAME = "KEY_PARAM_ACCOUNT_NAME" const val KEY_PARAM_BEHAVIOR = "KEY_PARAM_BEHAVIOR" const val KEY_PARAM_CONTENT_URI = "KEY_PARAM_CONTENT_URI" diff --git a/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java b/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java index f4fe04c35c6..68be5dc87b2 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java +++ b/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java @@ -119,5 +119,18 @@ static public class ProviderTableMeta implements BaseColumns { public static final String FILE_IS_DOWNLOADING = "is_downloading"; public static final String FILE_ETAG_IN_CONFLICT = "etag_in_conflict"; public static final String FILE_PRIVATE_LINK = "private_link"; + + // Columns of list_of_uploads table + public static final String UPLOAD_LOCAL_PATH = "local_path"; + public static final String UPLOAD_REMOTE_PATH = "remote_path"; + public static final String UPLOAD_ACCOUNT_NAME = "account_name"; + public static final String UPLOAD_FILE_SIZE = "file_size"; + public static final String UPLOAD_STATUS = "status"; + public static final String UPLOAD_LOCAL_BEHAVIOUR = "local_behaviour"; + public static final String UPLOAD_FORCE_OVERWRITE = "force_overwrite"; + public static final String UPLOAD_UPLOAD_END_TIMESTAMP = "upload_end_timestamp"; + public static final String UPLOAD_LAST_RESULT = "last_result"; + public static final String UPLOAD_CREATED_BY = "created_by"; + public static final String UPLOAD_TRANSFER_ID = "transfer_id"; } } diff --git a/owncloudData/src/main/java/com/owncloud/android/data/storage/LocalStorageProvider.kt b/owncloudData/src/main/java/com/owncloud/android/data/storage/LocalStorageProvider.kt index 6ba2611214e..99fa99c50f2 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/storage/LocalStorageProvider.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/storage/LocalStorageProvider.kt @@ -7,7 +7,7 @@ * @author Shashvat Kedia * @author Juan Carlos Garrote Gascón *

- * Copyright (C) 2021 ownCloud GmbH. + * Copyright (C) 2022 ownCloud GmbH. *

* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -29,6 +29,7 @@ import android.net.Uri import com.owncloud.android.data.extension.moveRecursively import timber.log.Timber import com.owncloud.android.domain.files.model.OCFile +import com.owncloud.android.domain.transfers.model.OCTransfer import java.io.File import java.util.concurrent.TimeUnit import kotlin.system.measureTimeMillis @@ -204,6 +205,28 @@ sealed class LocalStorageProvider(private val rootFolderName: String) { fileToMove.renameTo(targetFile) } + fun clearUnrelatedTemporalFiles(uploads: List, accountsNames: List) { + accountsNames.forEach { accountName -> + val temporalFolderForAccount = File(getTemporalPath(accountName)) + cleanTemporalRecursively(temporalFolderForAccount) { temporalFile -> + if (!uploads.map { it.localPath }.contains(temporalFile.absolutePath)) { + temporalFile.delete() + } + } + } + } + + private fun cleanTemporalRecursively(temporalFolder: File, deleteFileInCaseItIsNotNeeded: (file: File) -> Unit) { + temporalFolder.listFiles()?.forEach { temporalFile -> + if (temporalFile.isDirectory) { + cleanTemporalRecursively(temporalFile, deleteFileInCaseItIsNotNeeded) + } else { + deleteFileInCaseItIsNotNeeded(temporalFile) + } + + } + } + companion object { private const val LOGS_FOLDER_NAME = "/logs/" private const val TEMPORAL_FOLDER_NAME = "tmp" diff --git a/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/LocalTransferDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/LocalTransferDataSource.kt index b98e7ac3714..28968bc9605 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/LocalTransferDataSource.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/LocalTransferDataSource.kt @@ -36,9 +36,15 @@ interface LocalTransferDataSource { transferEndTimestamp: Long, lastResult: TransferResult ) + fun updateTransferStorageDirectoryInLocalPath( + id: Long, + oldDirectory: String, + newDirectory: String + ) fun removeTransferById(id: Long) fun removeAllTransfersFromAccount(accountName: String) fun getTransferById(id: Long): OCTransfer? + fun getAllTransfers(): List fun getAllTransfersAsLiveData(): LiveData> fun getLastTransferFor(remotePath: String, accountName: String): OCTransfer? fun getCurrentAndPendingTransfers(): List diff --git a/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSource.kt index 6c1232dae32..7c2e2b8b324 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSource.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSource.kt @@ -25,9 +25,11 @@ import androidx.lifecycle.Transformations import com.owncloud.android.data.transfers.datasources.LocalTransferDataSource import com.owncloud.android.data.transfers.db.OCTransferEntity import com.owncloud.android.data.transfers.db.TransferDao +import com.owncloud.android.domain.camerauploads.model.UploadBehavior import com.owncloud.android.domain.transfers.model.OCTransfer import com.owncloud.android.domain.transfers.model.TransferResult import com.owncloud.android.domain.transfers.model.TransferStatus +import com.owncloud.android.domain.transfers.model.UploadEnqueuedBy class OCLocalTransferDataSource( private val transferDao: TransferDao @@ -57,6 +59,14 @@ class OCLocalTransferDataSource( transferDao.updateTransferWhenFinished(id, status.value, transferEndTimestamp, lastResult.value) } + override fun updateTransferStorageDirectoryInLocalPath( + id: Long, + oldDirectory: String, + newDirectory: String + ) { + transferDao.updateTransferStorageDirectoryInLocalPath(id, oldDirectory, newDirectory) + } + override fun removeTransferById(id: Long) { transferDao.deleteTransferWithId(id) } @@ -69,6 +79,12 @@ class OCLocalTransferDataSource( return transferDao.getTransferWithId(id)?.toModel() } + override fun getAllTransfers(): List { + return transferDao.getAllTransfers().map { transferEntity -> + transferEntity.toModel() + } + } + override fun getAllTransfersAsLiveData(): LiveData> { return Transformations.map(transferDao.getAllTransfersAsLiveData()) { transferEntitiesList -> val transfers = transferEntitiesList.map { transferEntity -> @@ -130,11 +146,11 @@ class OCLocalTransferDataSource( accountName = accountName, fileSize = fileSize, status = TransferStatus.fromValue(status), - localBehaviour = localBehaviour, + localBehaviour = UploadBehavior.values()[localBehaviour], forceOverwrite = forceOverwrite, transferEndTimestamp = transferEndTimestamp, lastResult = lastResult?.let { TransferResult.fromValue(it) }, - createdBy = createdBy, + createdBy = UploadEnqueuedBy.values()[createdBy], transferId = transferId ) @@ -144,11 +160,11 @@ class OCLocalTransferDataSource( accountName = accountName, fileSize = fileSize, status = status.value, - localBehaviour = localBehaviour, + localBehaviour = localBehaviour.ordinal, forceOverwrite = forceOverwrite, transferEndTimestamp = transferEndTimestamp, lastResult = lastResult?.value, - createdBy = createdBy, + createdBy = createdBy.ordinal, transferId = transferId ).apply { this@toEntity.id?.let { this.id = it } } diff --git a/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/OCTransferEntity.kt b/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/OCTransferEntity.kt index f2fc9c2f927..3653c51aabf 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/OCTransferEntity.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/OCTransferEntity.kt @@ -20,9 +20,23 @@ package com.owncloud.android.data.transfers.db +import android.database.Cursor +import android.provider.BaseColumns._ID import androidx.room.Entity import androidx.room.PrimaryKey import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.TRANSFERS_TABLE_NAME +import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.UPLOAD_ACCOUNT_NAME +import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.UPLOAD_CREATED_BY +import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.UPLOAD_FILE_SIZE +import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.UPLOAD_FORCE_OVERWRITE +import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.UPLOAD_LAST_RESULT +import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.UPLOAD_LOCAL_BEHAVIOUR +import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.UPLOAD_LOCAL_PATH +import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.UPLOAD_REMOTE_PATH +import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.UPLOAD_STATUS +import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.UPLOAD_TRANSFER_ID +import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.UPLOAD_UPLOAD_END_TIMESTAMP +import com.owncloud.android.domain.transfers.model.TransferStatus @Entity( tableName = TRANSFERS_TABLE_NAME @@ -42,4 +56,32 @@ data class OCTransferEntity( ) { @PrimaryKey(autoGenerate = true) var id: Long = 0 + + companion object { + private const val LEGACY_UPLOAD_IN_PROGRESS = 0 + private const val LEGACY_UPLOAD_FAILED = 1 + + fun fromCursor(cursor: Cursor): OCTransferEntity { + val newStatus = when (cursor.getInt(cursor.getColumnIndexOrThrow(UPLOAD_STATUS))) { + LEGACY_UPLOAD_IN_PROGRESS -> TransferStatus.TRANSFER_QUEUED.value + LEGACY_UPLOAD_FAILED -> TransferStatus.TRANSFER_FAILED.value + else -> TransferStatus.TRANSFER_SUCCEEDED.value + } + return OCTransferEntity( + localPath = cursor.getString(cursor.getColumnIndexOrThrow(UPLOAD_LOCAL_PATH)), + remotePath = cursor.getString(cursor.getColumnIndexOrThrow(UPLOAD_REMOTE_PATH)), + accountName = cursor.getString(cursor.getColumnIndexOrThrow(UPLOAD_ACCOUNT_NAME)), + fileSize = cursor.getLong(cursor.getColumnIndexOrThrow(UPLOAD_FILE_SIZE)), + status = newStatus, + localBehaviour = cursor.getInt(cursor.getColumnIndexOrThrow(UPLOAD_LOCAL_BEHAVIOUR)), + forceOverwrite = cursor.getInt(cursor.getColumnIndexOrThrow(UPLOAD_FORCE_OVERWRITE)) == 1, + transferEndTimestamp = cursor.getLong(cursor.getColumnIndexOrThrow(UPLOAD_UPLOAD_END_TIMESTAMP)), + lastResult = cursor.getInt(cursor.getColumnIndexOrThrow(UPLOAD_LAST_RESULT)), + createdBy = cursor.getInt(cursor.getColumnIndexOrThrow(UPLOAD_CREATED_BY)), + transferId = cursor.getString(cursor.getColumnIndexOrThrow(UPLOAD_TRANSFER_ID)) + ).apply { + id = cursor.getLong(cursor.getColumnIndexOrThrow(_ID)) + } + } + } } diff --git a/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/TransferDao.kt b/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/TransferDao.kt index 86939a09bf5..a9caa2c207a 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/TransferDao.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/TransferDao.kt @@ -38,6 +38,9 @@ abstract class TransferDao { @Query(SELECT_TRANSFERS_WITH_STATUS) abstract fun getTransfersWithStatus(status: List): List + @Query(SELECT_ALL_TRANSFERS) + abstract fun getAllTransfers(): List + @Query(SELECT_ALL_TRANSFERS) abstract fun getAllTransfersAsLiveData(): LiveData> @@ -50,6 +53,9 @@ abstract class TransferDao { @Query(UPDATE_TRANSFER_WHEN_FINISHED) abstract fun updateTransferWhenFinished(id: Long, status: Int, transferEndTimestamp: Long, lastResult: Int) + @Query(UPDATE_TRANSFER_STORAGE_DIRECTORY) + abstract fun updateTransferStorageDirectoryInLocalPath(id: Long, oldDirectory: String, newDirectory: String) + @Query(DELETE_TRANSFER_WITH_ID) abstract fun deleteTransferWithId(id: Long) @@ -93,6 +99,11 @@ abstract class TransferDao { "lastResult = :lastResult " + "WHERE id = :id" + private const val UPDATE_TRANSFER_STORAGE_DIRECTORY = + "UPDATE $TRANSFERS_TABLE_NAME " + + "SET localPath = `REPLACE`(localPath, :oldDirectory, :newDirectory) " + + "WHERE id = :id" + private const val DELETE_TRANSFER_WITH_ID = "DELETE FROM $TRANSFERS_TABLE_NAME " + "WHERE id = :id" diff --git a/owncloudData/src/main/java/com/owncloud/android/data/transfers/repository/OCTransferRepository.kt b/owncloudData/src/main/java/com/owncloud/android/data/transfers/repository/OCTransferRepository.kt index 9a881859ba4..c41cdf76ffb 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/transfers/repository/OCTransferRepository.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/transfers/repository/OCTransferRepository.kt @@ -58,6 +58,18 @@ class OCTransferRepository( ) } + override fun updateTransferStorageDirectoryInLocalPath( + id: Long, + oldDirectory: String, + newDirectory: String + ) { + localTransferDataSource.updateTransferStorageDirectoryInLocalPath( + id = id, + oldDirectory = oldDirectory, + newDirectory = newDirectory + ) + } + override fun removeTransferById(id: Long) = localTransferDataSource.removeTransferById(id = id) @@ -67,6 +79,9 @@ class OCTransferRepository( override fun getTransferById(id: Long): OCTransfer? = localTransferDataSource.getTransferById(id = id) + override fun getAllTransfers(): List = + localTransferDataSource.getAllTransfers() + override fun getAllTransfersAsLiveData(): LiveData> = localTransferDataSource.getAllTransfersAsLiveData() diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/camerauploads/model/FolderBackUpConfiguration.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/camerauploads/model/FolderBackUpConfiguration.kt index edf5f7ab84f..2d45c74b6d4 100644 --- a/owncloudDomain/src/main/java/com/owncloud/android/domain/camerauploads/model/FolderBackUpConfiguration.kt +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/camerauploads/model/FolderBackUpConfiguration.kt @@ -16,6 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + package com.owncloud.android.domain.camerauploads.model data class FolderBackUpConfiguration( @@ -58,7 +59,6 @@ enum class UploadBehavior { companion object { private const val LEGACY_LOCAL_BEHAVIOUR_COPY = 0 private const val LEGACY_LOCAL_BEHAVIOUR_MOVE = 1 - private const val LEGACY_LOCAL_BEHAVIOUR_FORGET = 2 fun fromString(string: String): UploadBehavior { return if (string.equals("MOVE", ignoreCase = true)) { @@ -67,15 +67,5 @@ enum class UploadBehavior { COPY } } - - @Deprecated("Legacy Local Behavior. Remove asap") - fun fromLegacyLocalBehavior(oldLocalBehavior: Int): UploadBehavior { - return when (oldLocalBehavior) { - LEGACY_LOCAL_BEHAVIOUR_MOVE -> MOVE - LEGACY_LOCAL_BEHAVIOUR_COPY -> COPY - LEGACY_LOCAL_BEHAVIOUR_FORGET -> MOVE - else -> COPY - } - } } } diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/TransferRepository.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/TransferRepository.kt index 7dcf53b72e8..c06f53faf92 100644 --- a/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/TransferRepository.kt +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/TransferRepository.kt @@ -36,9 +36,15 @@ interface TransferRepository { transferEndTimestamp: Long, lastResult: TransferResult ) + fun updateTransferStorageDirectoryInLocalPath( + id: Long, + oldDirectory: String, + newDirectory: String + ) fun removeTransferById(id: Long) fun removeAllTransfersFromAccount(accountName: String) fun getTransferById(id: Long): OCTransfer? + fun getAllTransfers(): List fun getAllTransfersAsLiveData(): LiveData> fun getLastTransferFor(remotePath: String, accountName: String): OCTransfer? fun getCurrentAndPendingTransfers(): List diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/model/OCTransfer.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/model/OCTransfer.kt index a789373cd20..ad8b86a801c 100644 --- a/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/model/OCTransfer.kt +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/model/OCTransfer.kt @@ -21,6 +21,7 @@ package com.owncloud.android.domain.transfers.model import android.os.Parcelable +import com.owncloud.android.domain.camerauploads.model.UploadBehavior import kotlinx.parcelize.Parcelize import java.io.File @@ -32,11 +33,11 @@ data class OCTransfer( val accountName: String, val fileSize: Long, var status: TransferStatus, - val localBehaviour: Int, + val localBehaviour: UploadBehavior, val forceOverwrite: Boolean, val transferEndTimestamp: Long? = null, val lastResult: TransferResult? = null, - val createdBy: Int, + val createdBy: UploadEnqueuedBy, val transferId: String? = null ) : Parcelable { init { diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadEnqueuedBy.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/model/UploadEnqueuedBy.kt similarity index 70% rename from owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadEnqueuedBy.kt rename to owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/model/UploadEnqueuedBy.kt index 8a26adf6c0b..016e2192d7c 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadEnqueuedBy.kt +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/model/UploadEnqueuedBy.kt @@ -16,10 +16,8 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.owncloud.android.usecases.transfers.uploads - -import com.owncloud.android.workers.UploadFileFromContentUriWorker +package com.owncloud.android.domain.transfers.model /** * Select who enqueued the upload. It could be manually by the user or automatically by other workers within the app. @@ -33,12 +31,4 @@ enum class UploadEnqueuedBy { ENQUEUED_BY_USER, ENQUEUED_AS_CAMERA_UPLOAD_PICTURE, ENQUEUED_AS_CAMERA_UPLOAD_VIDEO; - - fun toTransferTag(): String { - return when (this) { - ENQUEUED_BY_USER -> UploadFileFromContentUriWorker.TRANSFER_TAG_MANUAL_UPLOAD - ENQUEUED_AS_CAMERA_UPLOAD_PICTURE -> UploadFileFromContentUriWorker.TRANSFER_TAG_CAMERA_UPLOAD - ENQUEUED_AS_CAMERA_UPLOAD_VIDEO -> UploadFileFromContentUriWorker.TRANSFER_TAG_CAMERA_UPLOAD - } - } } diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/usecases/GetAllTransfersUseCase.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/usecases/GetAllTransfersUseCase.kt new file mode 100644 index 00000000000..427cf6d6058 --- /dev/null +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/usecases/GetAllTransfersUseCase.kt @@ -0,0 +1,33 @@ +/** + * ownCloud Android client application + * + * @author Juan Carlos Garrote Gascón + * + * Copyright (C) 2022 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.owncloud.android.domain.transfers.usecases + +import com.owncloud.android.domain.BaseUseCase +import com.owncloud.android.domain.transfers.TransferRepository +import com.owncloud.android.domain.transfers.model.OCTransfer + +class GetAllTransfersUseCase( + private val transferRepository: TransferRepository, +) : BaseUseCase, Unit>() { + override fun run(params: Unit): List = + transferRepository.getAllTransfers() + +} diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/usecases/UpdatePendingUploadsPathUseCase.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/usecases/UpdatePendingUploadsPathUseCase.kt new file mode 100644 index 00000000000..c43d09aeb6a --- /dev/null +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/usecases/UpdatePendingUploadsPathUseCase.kt @@ -0,0 +1,42 @@ +/** + * ownCloud Android client application + * + * @author Juan Carlos Garrote Gascón + * + * Copyright (C) 2022 ownCloud GmbH. + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + *

+ * 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 General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.owncloud.android.domain.transfers.usecases + +import com.owncloud.android.domain.BaseUseCase +import com.owncloud.android.domain.transfers.TransferRepository + +class UpdatePendingUploadsPathUseCase( + private val transferRepository: TransferRepository, +) : BaseUseCase() { + + override fun run(params: Params) { + transferRepository.clearSuccessfulTransfers() + val storedUploads = transferRepository.getAllTransfers() + storedUploads.forEach { upload -> + transferRepository.updateTransferStorageDirectoryInLocalPath(upload.id!!, params.oldDirectory, params.newDirectory) + } + } + + data class Params( + val oldDirectory: String, + val newDirectory: String + ) +}