From b73c881513bddc0fe1a842bab9e12cc7799b4222 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 3 Dec 2025 10:56:28 +0100 Subject: [PATCH 1/2] fix: upload cancel & remove Signed-off-by: alperozturk --- app/src/main/AndroidManifest.xml | 3 - .../client/database/dao/UploadDao.kt | 2 +- .../upload/FileUploadBroadcastReceiver.kt | 55 +++++++++++++------ .../client/jobs/upload/FileUploadHelper.kt | 2 +- .../client/jobs/upload/FileUploadWorker.kt | 7 +-- .../client/jobs/upload/FileUploaderIntents.kt | 23 +------- .../jobs/upload/UploadBroadcastAction.kt | 54 ++++++++++++++++++ .../jobs/upload/UploadNotificationManager.kt | 18 ++---- .../utils/UploadErrorNotificationManager.kt | 12 ++-- .../android/ui/adapter/UploadListAdapter.java | 8 +-- .../ui/notifications/NotificationUtils.kt | 5 -- app/src/main/res/values/strings.xml | 1 + 12 files changed, 112 insertions(+), 78 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/client/jobs/upload/UploadBroadcastAction.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b140a8930ad3..940739adb944 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -303,9 +303,6 @@ - diff --git a/app/src/main/java/com/nextcloud/client/database/dao/UploadDao.kt b/app/src/main/java/com/nextcloud/client/database/dao/UploadDao.kt index deaa44c4b335..7f09f4aa0543 100644 --- a/app/src/main/java/com/nextcloud/client/database/dao/UploadDao.kt +++ b/app/src/main/java/com/nextcloud/client/database/dao/UploadDao.kt @@ -41,7 +41,7 @@ interface UploadDao { "WHERE ${ProviderTableMeta.UPLOADS_ACCOUNT_NAME} = :accountName " + "AND ${ProviderTableMeta.UPLOADS_REMOTE_PATH} = :remotePath" ) - fun deleteByAccountAndRemotePath(accountName: String, remotePath: String) + fun deleteByAccountAndRemotePath(remotePath: String, accountName: String) @Query( "SELECT * FROM " + ProviderTableMeta.UPLOADS_TABLE_NAME + diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastReceiver.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastReceiver.kt index 7f7df3a32cb3..3394d4d1212f 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastReceiver.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastReceiver.kt @@ -8,7 +8,6 @@ package com.nextcloud.client.jobs.upload import android.app.NotificationManager -import android.app.PendingIntent import android.content.BroadcastReceiver import android.content.Context import android.content.Intent @@ -22,34 +21,54 @@ class FileUploadBroadcastReceiver : BroadcastReceiver() { lateinit var uploadsStorageManager: UploadsStorageManager companion object { - private const val UPLOAD_ID = "UPLOAD_ID" - - fun getBroadcast(context: Context, id: Long): PendingIntent { - val intent = Intent(context, FileUploadBroadcastReceiver::class.java).apply { - putExtra(UPLOAD_ID, id) - setClass(context, FileUploadBroadcastReceiver::class.java) - setPackage(context.packageName) - } - - return PendingIntent.getBroadcast( - context, - id.toInt(), - intent, - PendingIntent.FLAG_IMMUTABLE - ) - } + // region cancel or remove actions + const val UPLOAD_ID = "UPLOAD_ID" + const val ACCOUNT_NAME = "ACCOUNT_NAME" + const val REMOTE_PATH = "REMOTE_PATH" + const val REMOVE = "REMOVE" + // endregion } @Suppress("ReturnCount") override fun onReceive(context: Context, intent: Intent) { MainApp.getAppComponent().inject(this) + if (intent.action == UploadBroadcastAction.CancelOrRemove::class.simpleName) { + cancelUpload(context, intent) + } + } + + private fun cancelUpload(context: Context, intent: Intent) { val uploadId = intent.getLongExtra(UPLOAD_ID, -1L) if (uploadId == -1L) { return } - uploadsStorageManager.removeUpload(uploadId) + val accountName = intent.getStringExtra(ACCOUNT_NAME) + if (accountName.isNullOrEmpty()) { + return + } + + val remotePath = intent.getStringExtra(REMOTE_PATH) + if (remotePath.isNullOrEmpty()) { + return + } + + val remove = intent.getBooleanExtra(REMOVE, false) + + FileUploadWorker.cancelCurrentUpload(remotePath, accountName, onCompleted = {}) + + if (remove) { + uploadsStorageManager.removeUpload(uploadId) + } else { + FileUploadHelper.instance().updateUploadStatus( + remotePath, + accountName, + UploadsStorageManager.UploadStatus.UPLOAD_CANCELLED + ) + } + + // dismiss notification val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager.cancel(uploadId.toInt()) } diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt index 4b3568a00a2a..566d80415c08 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt @@ -250,7 +250,7 @@ class FileUploadHelper { } fun removeFileUpload(remotePath: String, accountName: String) { - uploadsStorageManager.uploadDao.deleteByAccountAndRemotePath(accountName, remotePath) + uploadsStorageManager.uploadDao.deleteByAccountAndRemotePath(remotePath, accountName) } fun updateUploadStatus(remotePath: String, accountName: String, status: UploadStatus) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt index c29f9c6a63d9..7aba37b8b1eb 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt @@ -238,7 +238,7 @@ class FileUploadWorker( if (preferences.isGlobalUploadPaused) { Log_OC.d(TAG, "Upload is paused, skip uploading files!") notificationManager.notifyPaused( - intents.notificationStartIntent(null) + intents.openUploadListIntent(null) ) return@withContext Result.success() } @@ -256,8 +256,7 @@ class FileUploadWorker( val currentUploadIndex = (currentIndex + previouslyUploadedFileSize) notificationManager.prepareForStart( operation, - cancelPendingIntent = intents.startIntent(operation), - startIntent = intents.notificationStartIntent(operation), + startIntent = intents.openUploadListIntent(operation), currentUploadIndex = currentUploadIndex, totalUploadSize = totalUploadSize ) @@ -353,7 +352,7 @@ class FileUploadWorker( Log_OC.e(TAG, "Error uploading", e) result = RemoteOperationResult(e) } finally { - if (!isStopped || !result.isCancelled) { + if (!isStopped) { uploadsStorageManager.updateDatabaseUploadResult(result, operation) UploadErrorNotificationManager.handleResult( context, diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploaderIntents.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploaderIntents.kt index ad0101aa5d59..b8341f26cafe 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploaderIntents.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploaderIntents.kt @@ -12,31 +12,10 @@ import android.content.Context import android.content.Intent import com.owncloud.android.operations.UploadFileOperation import com.owncloud.android.ui.activity.UploadListActivity -import java.security.SecureRandom class FileUploaderIntents(private val context: Context) { - private val secureRandomGenerator = SecureRandom() - - fun startIntent(operation: UploadFileOperation): PendingIntent { - val intent = Intent( - context, - FileUploadHelper.UploadNotificationActionReceiver::class.java - ).apply { - putExtra(FileUploadWorker.EXTRA_ACCOUNT_NAME, operation.user.accountName) - putExtra(FileUploadWorker.EXTRA_REMOTE_PATH, operation.remotePath) - action = FileUploadWorker.ACTION_CANCEL_BROADCAST - } - - return PendingIntent.getBroadcast( - context, - secureRandomGenerator.nextInt(), - intent, - PendingIntent.FLAG_IMMUTABLE - ) - } - - fun notificationStartIntent(operation: UploadFileOperation?): PendingIntent { + fun openUploadListIntent(operation: UploadFileOperation?): PendingIntent { val intent = UploadListActivity.createIntent( operation?.file, operation?.user, diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/UploadBroadcastAction.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/UploadBroadcastAction.kt new file mode 100644 index 000000000000..d8cf3dadca1d --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/UploadBroadcastAction.kt @@ -0,0 +1,54 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.client.jobs.upload + +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import androidx.core.app.NotificationCompat +import com.owncloud.android.R +import com.owncloud.android.operations.UploadFileOperation + +sealed class UploadBroadcastAction { + data class CancelOrRemove(val operation: UploadFileOperation) : UploadBroadcastAction() { + fun cancelAction(context: Context): NotificationCompat.Action = NotificationCompat.Action( + R.drawable.ic_cancel, + context.getString(R.string.common_cancel), + getBroadcast(context, false) + ) + + fun removeAction(context: Context): NotificationCompat.Action = NotificationCompat.Action( + R.drawable.ic_delete, + context.getString(R.string.remove_upload), + getBroadcast(context, true) + ) + + @Suppress("MagicNumber") + private fun getBroadcast(context: Context, remove: Boolean): PendingIntent { + val intent = Intent(context, FileUploadBroadcastReceiver::class.java).apply { + putExtra(FileUploadBroadcastReceiver.UPLOAD_ID, operation.ocUploadId) + putExtra(FileUploadBroadcastReceiver.ACCOUNT_NAME, operation.user.accountName) + putExtra(FileUploadBroadcastReceiver.REMOTE_PATH, operation.remotePath) + putExtra(FileUploadBroadcastReceiver.REMOVE, remove) + action = CancelOrRemove::class.simpleName + + setClass(context, FileUploadBroadcastReceiver::class.java) + setPackage(context.packageName) + } + + val requestCode = if (remove) operation.ocUploadId.toInt() + 1000 else operation.ocUploadId.toInt() + + return PendingIntent.getBroadcast( + context, + requestCode, + intent, + PendingIntent.FLAG_IMMUTABLE + ) + } + } +} diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/UploadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/UploadNotificationManager.kt index b555b6fab83c..27ffd2e26ce2 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/UploadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/UploadNotificationManager.kt @@ -27,8 +27,7 @@ class UploadNotificationManager(private val context: Context, viewThemeUtils: Vi @Suppress("MagicNumber") fun prepareForStart( - uploadFileOperation: UploadFileOperation, - cancelPendingIntent: PendingIntent, + operation: UploadFileOperation, startIntent: PendingIntent, currentUploadIndex: Int, totalUploadSize: Int @@ -38,10 +37,10 @@ class UploadNotificationManager(private val context: Context, viewThemeUtils: Vi context.getString(R.string.upload_notification_manager_start_text), currentUploadIndex, totalUploadSize, - uploadFileOperation.fileName + operation.fileName ) } else { - uploadFileOperation.fileName + operation.fileName } val progressText = NumberFormatter.getPercentageText(0) @@ -52,17 +51,12 @@ class UploadNotificationManager(private val context: Context, viewThemeUtils: Vi setContentText(progressText) setOngoing(false) clearActions() - - addAction( - R.drawable.ic_action_cancel_grey, - context.getString(R.string.common_cancel), - cancelPendingIntent - ) - + addAction(UploadBroadcastAction.CancelOrRemove(operation).cancelAction(context)) + addAction(UploadBroadcastAction.CancelOrRemove(operation).removeAction(context)) setContentIntent(startIntent) } - if (!uploadFileOperation.isInstantPicture && !uploadFileOperation.isInstantVideo) { + if (!operation.isInstantPicture && !operation.isInstantVideo) { showNotification() } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt index 0ae1ec154d05..26e2a301e279 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/utils/UploadErrorNotificationManager.kt @@ -13,8 +13,8 @@ import android.content.Context import android.content.Intent import androidx.core.app.NotificationCompat import com.nextcloud.client.jobs.notification.WorkerNotificationManager -import com.nextcloud.client.jobs.upload.FileUploadBroadcastReceiver import com.nextcloud.client.jobs.upload.FileUploadHelper +import com.nextcloud.client.jobs.upload.UploadBroadcastAction import com.nextcloud.utils.extensions.isFileSpecificError import com.owncloud.android.R import com.owncloud.android.authentication.AuthenticatorActivity @@ -100,13 +100,12 @@ object UploadErrorNotificationManager { context.getString(R.string.upload_list_resolve_conflict), conflictResolvePendingIntent(context, operation) ) - addAction( - R.drawable.ic_delete, - context.getString(R.string.upload_list_cancel_upload), - FileUploadBroadcastReceiver.getBroadcast(context, operation.ocUploadId) - ) } + addAction(UploadBroadcastAction.CancelOrRemove(operation).cancelAction(context)) + + addAction(UploadBroadcastAction.CancelOrRemove(operation).removeAction(context)) + result.code.takeIf { it == ResultCode.UNAUTHORIZED }?.let { setContentIntent(credentialPendingIntent(context, operation)) } @@ -119,6 +118,7 @@ object UploadErrorNotificationManager { else -> R.string.uploader_upload_failed_ticker } + @Suppress("DEPRECATION") private fun credentialPendingIntent(context: Context, operation: UploadFileOperation): PendingIntent { val intent = Intent(context, AuthenticatorActivity::class.java).apply { putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, operation.user.toPlatformAccount()) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java index 5f30c45ac9b8..fac48e303d2d 100755 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java @@ -52,7 +52,6 @@ import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.adapter.progressListener.UploadProgressListener; -import com.owncloud.android.ui.notifications.NotificationUtils; import com.owncloud.android.ui.preview.PreviewImageFragment; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.MimeTypeUtil; @@ -1077,17 +1076,14 @@ public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) { } public void cancelOldErrorNotification(OCUpload upload) { - if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) parentActivity.getSystemService(parentActivity.NOTIFICATION_SERVICE); + mNotificationManager = (NotificationManager) parentActivity.getSystemService(Context.NOTIFICATION_SERVICE); } if (upload == null) { return; } - mNotificationManager.cancel(NotificationUtils.createUploadNotificationTag(upload.getRemotePath(), upload.getLocalPath()), - FileUploadWorker.NOTIFICATION_ERROR_ID); + mNotificationManager.cancel((int) upload.getUploadId()); } - } diff --git a/app/src/main/java/com/owncloud/android/ui/notifications/NotificationUtils.kt b/app/src/main/java/com/owncloud/android/ui/notifications/NotificationUtils.kt index 61fbc9df5b3c..a116937bebcb 100644 --- a/app/src/main/java/com/owncloud/android/ui/notifications/NotificationUtils.kt +++ b/app/src/main/java/com/owncloud/android/ui/notifications/NotificationUtils.kt @@ -11,8 +11,6 @@ */ package com.owncloud.android.ui.notifications -import com.owncloud.android.datamodel.OCFile - object NotificationUtils { const val NOTIFICATION_CHANNEL_GENERAL: String = "NOTIFICATION_CHANNEL_GENERAL" const val NOTIFICATION_CHANNEL_DOWNLOAD: String = "NOTIFICATION_CHANNEL_DOWNLOAD" @@ -25,9 +23,6 @@ object NotificationUtils { const val NOTIFICATION_CHANNEL_OFFLINE_OPERATIONS: String = "NOTIFICATION_CHANNEL_OFFLINE_OPERATIONS" const val NOTIFICATION_CHANNEL_CONTENT_OBSERVER: String = "NOTIFICATION_CHANNEL_CONTENT_OBSERVER" - fun createUploadNotificationTag(file: OCFile): String = - createUploadNotificationTag(file.remotePath, file.storagePath) - @JvmStatic fun createUploadNotificationTag(remotePath: String?, localPath: String): String = remotePath + localPath } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 806897f4d162..46448a7ddbb9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1394,6 +1394,7 @@ Secure sharing is not set up for this user Resharing is not allowed during secure file drop Sync + Remove Internal two way sync Manage internal folders for two way sync Not yet, soon to be synced From 3fedca14dfa48bf63914e745164c9279af683de2 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 3 Dec 2025 11:18:55 +0100 Subject: [PATCH 2/2] fix codacy Signed-off-by: alperozturk --- .../nextcloud/client/jobs/upload/FileUploadBroadcastReceiver.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastReceiver.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastReceiver.kt index 3394d4d1212f..dd50a8b94e94 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastReceiver.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadBroadcastReceiver.kt @@ -38,6 +38,7 @@ class FileUploadBroadcastReceiver : BroadcastReceiver() { } } + @Suppress("ReturnCount") private fun cancelUpload(context: Context, intent: Intent) { val uploadId = intent.getLongExtra(UPLOAD_ID, -1L) if (uploadId == -1L) {