Fix tracking current download status

Signed-off-by: alperozturk <alper_ozturk@proton.me>
This commit is contained in:
alperozturk 2024-01-05 11:06:04 +01:00 committed by Alper Öztürk
parent bb0fae654f
commit de4f673740
11 changed files with 92 additions and 128 deletions

View file

@ -63,7 +63,7 @@ class FileDownloadHelper {
return backgroundJobManager.isStartFileDownloadJobScheduled(
user,
file
)
) || FileDownloadWorker.isDownloading(user, file)
}
fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) {

View file

@ -24,6 +24,7 @@ package com.nextcloud.client.files.downloader
import android.accounts.Account
import android.accounts.AccountManager
import android.accounts.OnAccountsUpdateListener
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.Context
import androidx.core.util.component1
@ -34,8 +35,8 @@ import androidx.work.WorkerParameters
import com.nextcloud.client.account.User
import com.nextcloud.client.account.UserAccountManager
import com.nextcloud.java.util.Optional
import com.nextcloud.model.DownloadWorkerState
import com.nextcloud.model.DownloadWorkerStateLiveData
import com.nextcloud.model.WorkerState
import com.nextcloud.model.WorkerStateLiveData
import com.owncloud.android.datamodel.FileDataStorageManager
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.datamodel.UploadsStorageManager
@ -66,8 +67,10 @@ class FileDownloadWorker(
companion object {
private val TAG = FileDownloadWorker::class.java.simpleName
@SuppressLint("StaticFieldLeak")
private var currentDownload: DownloadFileOperation? = null
const val FILES_SEPARATOR = ","
const val WORKER_TAG = "WORKER_TAG"
const val FOLDER_PATH = "FOLDER_PATH"
const val USER_NAME = "USER"
const val FILE_PATH = "FILE_PATH"
@ -84,6 +87,11 @@ class FileDownloadWorker(
const val EXTRA_LINKED_TO_PATH = "LINKED_TO"
const val ACCOUNT_NAME = "ACCOUNT_NAME"
fun isDownloading(user: User, file: OCFile): Boolean {
return currentDownload?.file?.fileId == file.fileId &&
currentDownload?.user?.accountName == user.accountName
}
fun getDownloadAddedMessage(): String {
return FileDownloadWorker::class.java.name + "DOWNLOAD_ADDED"
}
@ -93,7 +101,7 @@ class FileDownloadWorker(
}
}
private var currentDownload: DownloadFileOperation? = null
private val pendingDownloads = IndexedForest<DownloadFileOperation>()
private var conflictUploadId: Long? = null
private var lastPercent = 0
private val intents = FileDownloadIntents(context)
@ -106,8 +114,6 @@ class FileDownloadWorker(
private var user: User? = null
private var folder: OCFile? = null
private var isAnyOperationFailed = true
private var workerTag: String? = null
private val pendingDownloads = IndexedForest<DownloadFileOperation>()
@Suppress("TooGenericExceptionCaught")
override fun doWork(): Result {
@ -147,12 +153,11 @@ class FileDownloadWorker(
}
private fun setWorkerState(user: User?) {
val worker = DownloadWorkerState(workerTag ?: "", user, pendingDownloads)
DownloadWorkerStateLiveData.instance().addWorker(worker)
WorkerStateLiveData.instance().setWorkState(WorkerState.Download(user, currentDownload))
}
private fun setIdleWorkerState() {
DownloadWorkerStateLiveData.instance().removeWorker(workerTag ?: "")
WorkerStateLiveData.instance().setWorkState(WorkerState.Idle)
}
private fun notifyForFolderResult(folder: OCFile) {
@ -165,7 +170,6 @@ class FileDownloadWorker(
val files = getFiles()
val downloadType = getDownloadType()
workerTag = inputData.keyValueMap[WORKER_TAG] as String? ?: ""
conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long?
val behaviour = inputData.keyValueMap[BEHAVIOUR] as String? ?: ""
@ -216,6 +220,7 @@ class FileDownloadWorker(
it.value.payload?.cancel()
}
pendingDownloads.all.clear()
currentDownload = null
}
private fun setUser() {

View file

@ -34,7 +34,6 @@ import androidx.work.PeriodicWorkRequest
import androidx.work.WorkInfo
import androidx.work.WorkManager
import androidx.work.workDataOf
import com.google.gson.Gson
import com.nextcloud.client.account.User
import com.nextcloud.client.core.Clock
import com.nextcloud.client.di.Injectable
@ -42,7 +41,6 @@ import com.nextcloud.client.documentscan.GeneratePdfFromImagesWork
import com.nextcloud.client.files.downloader.FileDownloadWorker
import com.nextcloud.client.preferences.AppPreferences
import com.nextcloud.utils.extensions.isWorkScheduled
import com.owncloud.android.datamodel.FileDataStorageManager
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.operations.DownloadType
import java.util.Date
@ -549,7 +547,6 @@ internal class BackgroundJobManagerImpl(
val tag = startFileDownloadJobTag(user, file)
val data = workDataOf(
FileDownloadWorker.WORKER_TAG to tag,
FileDownloadWorker.USER_NAME to user.accountName,
FileDownloadWorker.FILE_PATH to file.remotePath,
FileDownloadWorker.BEHAVIOUR to behaviour,

View file

@ -1,71 +0,0 @@
/*
* Nextcloud Android client application
*
* @author Alper Ozturk
* Copyright (C) 2023 Alper Ozturk
* Copyright (C) 2023 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.nextcloud.model
import androidx.lifecycle.LiveData
import com.nextcloud.client.account.User
import com.owncloud.android.datamodel.OCFile
class DownloadWorkerStateLiveData private constructor(): LiveData<ArrayList<DownloadWorkerState>>() {
private var workers: ArrayList<DownloadWorkerState> = arrayListOf()
fun isDownloading(user: User?, file: OCFile?): Boolean {
if (user == null || file == null) {
return false
}
var result = false
workers.forEach { downloadState ->
downloadState.pendingDownloads?.all?.forEach { download ->
result = download.value?.payload?.file?.fileId == file.fileId
}
}
return result
}
fun removeWorker(tag: String) {
workers.forEach {
if (it.tag == tag) {
workers.remove(it)
}
}
postValue(workers)
}
fun addWorker(state: DownloadWorkerState) {
workers.add(state)
postValue(workers)
}
companion object {
private var instance: DownloadWorkerStateLiveData? = null
fun instance(): DownloadWorkerStateLiveData {
return instance ?: synchronized(this) {
instance ?: DownloadWorkerStateLiveData().also { instance = it }
}
}
}
}

View file

@ -22,7 +22,9 @@
package com.nextcloud.model
import com.nextcloud.client.account.User
import com.owncloud.android.files.services.IndexedForest
import com.owncloud.android.operations.DownloadFileOperation
data class DownloadWorkerState(var tag: String, var user: User?, var pendingDownloads: IndexedForest<DownloadFileOperation>?)
sealed class WorkerState {
object Idle : WorkerState()
class Download(var user: User?, var currentDownload: DownloadFileOperation?) : WorkerState()
}

View file

@ -0,0 +1,41 @@
/*
* Nextcloud Android client application
*
* @author Alper Ozturk
* Copyright (C) 2023 Alper Ozturk
* Copyright (C) 2023 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.nextcloud.model
import androidx.lifecycle.LiveData
class WorkerStateLiveData private constructor() : LiveData<WorkerState>() {
fun setWorkState(state: WorkerState) {
postValue(state)
}
companion object {
private var instance: WorkerStateLiveData? = null
fun instance(): WorkerStateLiveData {
return instance ?: synchronized(this) {
instance ?: WorkerStateLiveData().also { instance = it }
}
}
}
}

View file

@ -73,7 +73,8 @@ import com.nextcloud.client.network.ConnectivityService;
import com.nextcloud.client.preferences.AppPreferences;
import com.nextcloud.client.utils.IntentUtil;
import com.nextcloud.java.util.Optional;
import com.nextcloud.model.DownloadWorkerStateLiveData;
import com.nextcloud.model.WorkerState;
import com.nextcloud.model.WorkerStateLiveData;
import com.nextcloud.utils.extensions.BundleExtensionsKt;
import com.nextcloud.utils.extensions.IntentExtensionsKt;
import com.nextcloud.utils.view.FastScrollUtils;
@ -1562,8 +1563,8 @@ public class FileDisplayActivity extends FileActivity
}
private void observeDownloadWorkerState() {
DownloadWorkerStateLiveData.Companion.instance().observe(this, state -> {
if (!state.isEmpty()) {
WorkerStateLiveData.Companion.instance().observe(this, state -> {
if (state instanceof WorkerState.Download) {
Log_OC.d(TAG, "Download worker started");
handleDownloadWorkerState();
}

View file

@ -37,6 +37,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.view.MenuItem;
import android.view.View;
import com.google.common.collect.Sets;
import com.nextcloud.client.account.User;
import com.nextcloud.client.account.UserAccountManager;
@ -44,8 +45,8 @@ import com.nextcloud.client.files.downloader.FileDownloadHelper;
import com.nextcloud.client.jobs.BackgroundJobManager;
import com.nextcloud.client.onboarding.FirstRunActivity;
import com.nextcloud.java.util.Optional;
import com.nextcloud.model.DownloadWorkerState;
import com.nextcloud.model.DownloadWorkerStateLiveData;
import com.nextcloud.model.WorkerState;
import com.nextcloud.model.WorkerStateLiveData;
import com.nextcloud.utils.extensions.BundleExtensionsKt;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
@ -54,7 +55,6 @@ import com.owncloud.android.datamodel.ArbitraryDataProvider;
import com.owncloud.android.datamodel.ArbitraryDataProviderImpl;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.files.services.FileUploader;
import com.owncloud.android.files.services.IndexedForest;
import com.owncloud.android.lib.common.OwnCloudAccount;
import com.owncloud.android.lib.common.UserInfo;
import com.owncloud.android.lib.common.utils.Log_OC;
@ -115,7 +115,8 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap
private ArbitraryDataProvider arbitraryDataProvider;
private boolean multipleAccountsSupported;
private final ArrayList<DownloadWorkerState> downloadWorkerStates = new ArrayList<>();
private String workerAccountName;
private DownloadFileOperation workerCurrentDownload;
@Inject BackgroundJobManager backgroundJobManager;
@Inject UserAccountManager accountManager;
@ -164,7 +165,7 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap
recyclerView.setAdapter(userListAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
initializeComponentGetters();
observeDownloadWorkerState();
observeWorkerState();
}
@ -341,7 +342,7 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap
mUploaderBinder.cancel(accountName);
}
cancelAllDownloadsForAccount();
FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload);
}
User currentUser = getUserAccountManager().getUser();
@ -409,20 +410,6 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap
return new ManageAccountsServiceConnection();
}
private void cancelAllDownloadsForAccount() {
for (DownloadWorkerState workerState : downloadWorkerStates) {
User currentUser = workerState.getUser();
IndexedForest<DownloadFileOperation> pendingDownloads = workerState.getPendingDownloads();
if (currentUser != null && pendingDownloads != null) {
pendingDownloads.getAll().values().forEach((value) -> {
DownloadFileOperation operation = value.getPayload();
FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(currentUser.getAccountName(), operation);
});
}
}
}
private void performAccountRemoval(User user) {
// disable account in recycler view
for (int i = 0; i < userListAdapter.getItemCount(); i++) {
@ -445,7 +432,8 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap
mUploaderBinder.cancel(user);
}
cancelAllDownloadsForAccount();
FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload);
backgroundJobManager.startAccountRemovalJob(user.getAccountName(), false);
// immediately select a new account
@ -529,10 +517,13 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap
}
}
private void observeDownloadWorkerState() {
DownloadWorkerStateLiveData.Companion.instance().observe(this, state -> {
private void observeWorkerState() {
WorkerStateLiveData.Companion.instance().observe(this, state -> {
if (state instanceof WorkerState.Download) {
Log_OC.d(TAG, "Download worker started");
downloadWorkerStates.addAll(state);
workerAccountName = ((WorkerState.Download) state).getUser().getAccountName();
workerCurrentDownload = ((WorkerState.Download) state).getCurrentDownload();
}
});
}

View file

@ -31,7 +31,6 @@ import android.os.Looper
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.LifecycleOwner
import com.afollestad.sectionedrecyclerview.SectionedRecyclerViewAdapter
import com.afollestad.sectionedrecyclerview.SectionedViewHolder
import com.nextcloud.client.account.User

View file

@ -34,7 +34,6 @@ import com.nextcloud.android.common.ui.theme.utils.ColorRole
import com.nextcloud.client.account.User
import com.nextcloud.client.files.downloader.FileDownloadHelper
import com.nextcloud.client.preferences.AppPreferences
import com.nextcloud.model.DownloadWorkerStateLiveData
import com.nextcloud.utils.extensions.createRoundedOutline
import com.owncloud.android.R
import com.owncloud.android.datamodel.FileDataStorageManager
@ -344,26 +343,25 @@ class OCFileListDelegate(
val operationsServiceBinder = transferServiceGetter.operationsServiceBinder
val fileUploaderBinder = transferServiceGetter.fileUploaderBinder
val isDownloading = if (file.isFolder) {
FileDownloadHelper.instance().isDownloading(user, file)
} else {
DownloadWorkerStateLiveData.instance().isDownloading(user, file)
}
val icon: Int? = when {
operationsServiceBinder?.isSynchronizing(user, file) == true ||
isDownloading ||
FileDownloadHelper.instance().isDownloading(user, file) ||
fileUploaderBinder?.isUploading(user, file) == true -> {
// synchronizing, downloading or uploading
R.drawable.ic_synchronizing
}
file.etagInConflict != null -> {
R.drawable.ic_synchronizing_error
}
file.isDown -> {
R.drawable.ic_synced
}
else -> { null }
else -> {
null
}
}
gridViewHolder.localFileIndicator.run {

View file

@ -41,7 +41,8 @@ import com.nextcloud.client.files.downloader.FileDownloadHelper;
import com.nextcloud.client.files.downloader.FileDownloadWorker;
import com.nextcloud.client.preferences.AppPreferences;
import com.nextcloud.java.util.Optional;
import com.nextcloud.model.DownloadWorkerStateLiveData;
import com.nextcloud.model.WorkerState;
import com.nextcloud.model.WorkerStateLiveData;
import com.nextcloud.utils.extensions.IntentExtensionsKt;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
@ -306,8 +307,8 @@ public class PreviewImageActivity extends FileActivity implements
}
private void observeDownloadWorkerState() {
DownloadWorkerStateLiveData.Companion.instance().observe(this, state -> {
if (!state.isEmpty()) {
WorkerStateLiveData.Companion.instance().observe(this, state -> {
if (state instanceof WorkerState.Download) {
Log_OC.d(TAG, "Download worker started");
isDownloadWorkStarted = true;