@@ -19,13 +19,14 @@ import com.nextcloud.client.database.entity.toOCUpload
1919import com.nextcloud.client.database.entity.toUploadEntity
2020import com.nextcloud.client.device.BatteryStatus
2121import com.nextcloud.client.device.PowerManagementService
22+ import com.nextcloud.client.di.ApplicationScope
2223import com.nextcloud.client.jobs.BackgroundJobManager
2324import com.nextcloud.client.network.Connectivity
2425import com.nextcloud.client.network.ConnectivityService
2526import com.nextcloud.client.notifications.AppWideNotificationManager
2627import com.nextcloud.utils.extensions.checkWCFRestrictions
28+ import com.nextcloud.utils.extensions.createOwncloudClient
2729import com.nextcloud.utils.extensions.getUploadIds
28- import com.nextcloud.utils.extensions.isAnonymous
2930import com.nextcloud.utils.extensions.isLastResultConflictError
3031import com.nextcloud.utils.extensions.isSame
3132import com.owncloud.android.MainApp
@@ -38,7 +39,6 @@ import com.owncloud.android.db.OCUpload
3839import com.owncloud.android.db.UploadResult
3940import com.owncloud.android.files.services.NameCollisionPolicy
4041import com.owncloud.android.lib.common.OwnCloudClient
41- import com.owncloud.android.lib.common.OwnCloudClientFactory
4242import com.owncloud.android.lib.common.network.OnDatatransferProgressListener
4343import com.owncloud.android.lib.common.operations.RemoteOperationResult
4444import com.owncloud.android.lib.common.utils.Log_OC
@@ -56,7 +56,7 @@ import kotlinx.coroutines.Dispatchers
5656import kotlinx.coroutines.launch
5757import kotlinx.coroutines.withContext
5858import java.io.File
59- import java.util.concurrent.Semaphore
59+ import java.util.concurrent.atomic.AtomicBoolean
6060import javax.inject.Inject
6161
6262@Suppress(" TooManyFunctions" )
@@ -74,26 +74,28 @@ class FileUploadHelper {
7474 @Inject
7575 lateinit var fileStorageManager: FileDataStorageManager
7676
77- private val ioScope = CoroutineScope (Dispatchers .IO )
77+ @Inject
78+ @ApplicationScope
79+ lateinit var appScope: CoroutineScope
7880
7981 init {
8082 MainApp .getAppComponent().inject(this )
8183 }
8284
85+ private val uploadActionHandler = UploadListAdapterActionHandler ()
86+
8387 companion object {
8488 private val TAG = FileUploadWorker ::class .java.simpleName
8589
8690 const val MAX_FILE_COUNT = 500
8791
8892 val mBoundListeners = HashMap <String , OnDatatransferProgressListener >()
8993
90- private var instance : FileUploadHelper ? = null
94+ private val retryInProgress = AtomicBoolean ( false )
9195
92- private val retryFailedUploadsSemaphore = Semaphore ( 1 )
96+ private val sharedInstance : FileUploadHelper by lazy { FileUploadHelper () }
9397
94- fun instance (): FileUploadHelper = instance ? : synchronized(this ) {
95- instance ? : FileUploadHelper ().also { instance = it }
96- }
98+ fun instance (): FileUploadHelper = sharedInstance
9799
98100 fun buildRemoteName (accountName : String , remotePath : String ): String = accountName + remotePath
99101 }
@@ -122,21 +124,17 @@ class FileUploadHelper {
122124 connectivityService : ConnectivityService ,
123125 accountManager : UserAccountManager ,
124126 powerManagementService : PowerManagementService
125- ): Boolean {
126- if (! retryFailedUploadsSemaphore.tryAcquire( )) {
127+ ) {
128+ if (! retryInProgress.compareAndSet( false , true )) {
127129 Log_OC .d(TAG , " skipping retryFailedUploads, already running" )
128- return true
130+ return
129131 }
130132
131- var isUploadStarted = false
132133 val capability = fileStorageManager.getCapability(accountManager.user)
133134
134- try {
135- ioScope.launch {
135+ appScope.launch {
136+ try {
136137 val uploads = getUploadsByStatus(null , UploadStatus .UPLOAD_FAILED , capability)
137- if (uploads.isNotEmpty()) {
138- isUploadStarted = true
139- }
140138
141139 retryUploads(
142140 uploadsStorageManager,
@@ -145,12 +143,12 @@ class FileUploadHelper {
145143 powerManagementService,
146144 uploads
147145 )
146+ } finally {
147+ // Reset only after retry processing has completely finished so the guard covers
148+ // coroutine execution, not just its launch. This keeps a single retry running at a time.
149+ retryInProgress.set(false )
148150 }
149- } finally {
150- retryFailedUploadsSemaphore.release()
151151 }
152-
153- return isUploadStarted
154152 }
155153
156154 suspend fun retryCancelledUploads (
@@ -185,21 +183,13 @@ class FileUploadHelper {
185183 val batteryStatus = powerManagementService.battery
186184
187185 val uploadsToRetry = mutableListOf<Long >()
188-
189- val currentAccount = accountManager.currentAccount
190- val context = MainApp .getAppContext()
191- var ownCloudClient: OwnCloudClient ? = null
192- if (! currentAccount.isAnonymous(context)) {
193- ownCloudClient =
194- OwnCloudClientFactory .createOwnCloudClient(accountManager.currentAccount, MainApp .getAppContext())
195- }
196- val uploadActionHandler = UploadListAdapterActionHandler ()
186+ val client = accountManager.createOwncloudClient()
197187
198188 for (upload in uploads) {
199189 if (upload.isLastResultConflictError()) {
200- ownCloudClient ?.let {
190+ client ?.let {
201191 conflictHandlingResult =
202- uploadActionHandler.handleConflict(upload, ownCloudClient , uploadsStorageManager)
192+ uploadActionHandler.handleConflict(upload, client = it , uploadsStorageManager)
203193 }
204194 continue
205195 }
@@ -214,7 +204,7 @@ class FileUploadHelper {
214204
215205 if (uploadResult != UploadResult .UPLOADED ) {
216206 if (upload.lastResult != uploadResult) {
217- // Setting Upload status else cancelled uploads will behave wrong, when retrying
207+ // Setting Upload status else canceled uploads will behave wrong, when retrying
218208 // Needs to happen first since lastResult wil be overwritten by setter
219209 upload.uploadStatus = UploadStatus .UPLOAD_FAILED
220210
@@ -345,7 +335,7 @@ class FileUploadHelper {
345335 status : UploadStatus ,
346336 onCompleted : () -> Unit = {}
347337 ) {
348- ioScope .launch {
338+ appScope .launch {
349339 uploadsStorageManager.uploadDao.updateStatus(remotePath, accountName, status.value)
350340 onCompleted()
351341 }
@@ -531,7 +521,7 @@ class FileUploadHelper {
531521 * @param user Needed for creating client
532522 */
533523 fun removeDuplicatedFile (duplicatedFile : OCFile , client : OwnCloudClient , user : User , onCompleted : () -> Unit ) {
534- ioScope .launch {
524+ appScope .launch {
535525 val removeFileOperation = RemoveFileOperation (
536526 duplicatedFile,
537527 false ,
0 commit comments