From e392ad3f75004779edd2c676b0860e84da60ae8b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 09:17:16 +0100 Subject: [PATCH 001/189] Create download worker Signed-off-by: alperozturk --- .../client/files/downloader/DownloadWorker.kt | 39 ++++ .../files/services/FileDownloader.java | 210 +++++++----------- 2 files changed, 123 insertions(+), 126 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt new file mode 100644 index 000000000000..70cfe01e674a --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt @@ -0,0 +1,39 @@ +/* + * 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 . + */ + +package com.nextcloud.client.files.downloader + +import android.content.Context +import android.content.Intent +import androidx.work.Worker +import androidx.work.WorkerParameters +import com.owncloud.android.files.services.FileDownloader + +class DownloadWorker( + private val context: Context, + params: WorkerParameters, + private val intent: Intent, + private val fileDownloader: FileDownloader, +) : Worker(context, params) { + override fun doWork(): Result { + TODO("Not yet implemented") + } +} diff --git a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java index b6b2c8c12344..d0db5d7761ad 100644 --- a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java +++ b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java @@ -23,6 +23,7 @@ import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.OnAccountsUpdateListener; +import android.app.Activity; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -88,8 +89,13 @@ import dagger.android.AndroidInjection; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -public class FileDownloader extends Service - implements OnDatatransferProgressListener, OnAccountsUpdateListener { +import static android.content.Context.NOTIFICATION_SERVICE; + +public class FileDownloader implements OnDatatransferProgressListener, OnAccountsUpdateListener { + + private final Activity activity; + private final Intent intent; + private final int startId; public static final String EXTRA_USER = "USER"; public static final String EXTRA_FILE = "FILE"; @@ -140,26 +146,25 @@ public static String getDownloadFinishMessage() { return FileDownloader.class.getName() + DOWNLOAD_FINISH_MESSAGE; } - /** - * Service initialization - */ - @Override - public void onCreate() { - super.onCreate(); - AndroidInjection.inject(this); + public FileDownloader(Activity activity, Intent intent, int startId) { + this.activity = activity; + this.intent = intent; + this.startId = startId; + + AndroidInjection.inject(activity); Log_OC.d(TAG, "Creating service"); - mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); HandlerThread thread = new HandlerThread("FileDownloaderThread", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper, this); mBinder = new FileDownloaderBinder(); - NotificationCompat.Builder builder = NotificationUtils.newNotificationBuilder(this, viewThemeUtils).setContentTitle( - getApplicationContext().getResources().getString(R.string.app_name)) - .setContentText(getApplicationContext().getResources().getString(R.string.foreground_service_download)) + NotificationCompat.Builder builder = NotificationUtils.newNotificationBuilder(activity, viewThemeUtils).setContentTitle( + activity.getResources().getString(R.string.app_name)) + .setContentText(activity.getResources().getString(R.string.foreground_service_download)) .setSmallIcon(R.drawable.notification_icon) - .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.notification_icon)); + .setLargeIcon(BitmapFactory.decodeResource(activity.getResources(), R.drawable.notification_icon)); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { @@ -169,16 +174,13 @@ public void onCreate() { mNotification = builder.build(); // add AccountsUpdatedListener - AccountManager am = AccountManager.get(getApplicationContext()); + AccountManager am = AccountManager.get(activity); am.addOnAccountsUpdatedListener(this, null, false); } - /** - * Service clean up - */ @Override - public void onDestroy() { + protected void finalize() throws Throwable { Log_OC.v(TAG, "Destroying service"); mBinder = null; mServiceHandler = null; @@ -187,94 +189,53 @@ public void onDestroy() { mNotificationManager = null; // remove AccountsUpdatedListener - AccountManager am = AccountManager.get(getApplicationContext()); + AccountManager am = AccountManager.get(activity); am.removeOnAccountsUpdatedListener(this); - super.onDestroy(); + super.finalize(); } + public void download() { + final User user = IntentExtensionsKt.getParcelableArgument(intent, EXTRA_USER, User.class); + final OCFile file = IntentExtensionsKt.getParcelableArgument(intent, EXTRA_FILE, OCFile.class); + final String behaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); - /** - * Entry point to add one or several files to the queue of downloads. - *

- * New downloads are added calling to startService(), resulting in a call to this method. This ensures the service - * will keep on working although the caller activity goes away. - */ - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - Log_OC.d(TAG, "Starting command with id " + startId); - - ForegroundServiceHelper.INSTANCE.startService(this, FOREGROUND_SERVICE_ID, mNotification, ForegroundServiceType.DataSync); - - if (intent == null || !intent.hasExtra(EXTRA_USER) || !intent.hasExtra(EXTRA_FILE)) { - Log_OC.e(TAG, "Not enough information provided in intent"); - return START_NOT_STICKY; - } else { - final User user = IntentExtensionsKt.getParcelableArgument(intent, EXTRA_USER, User.class); - final OCFile file = IntentExtensionsKt.getParcelableArgument(intent, EXTRA_FILE, OCFile.class); - final String behaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); - - DownloadType downloadType = DownloadType.DOWNLOAD; - if (intent.hasExtra(DOWNLOAD_TYPE)) { - downloadType = IntentExtensionsKt.getSerializableArgument(intent, DOWNLOAD_TYPE, DownloadType.class); - } - String activityName = intent.getStringExtra(SendShareDialog.ACTIVITY_NAME); - String packageName = intent.getStringExtra(SendShareDialog.PACKAGE_NAME); - conflictUploadId = intent.getLongExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, -1); - AbstractList requestedDownloads = new Vector(); - try { - DownloadFileOperation newDownload = new DownloadFileOperation(user, - file, - behaviour, - activityName, - packageName, - getBaseContext(), - downloadType); - newDownload.addDatatransferProgressListener(this); - newDownload.addDatatransferProgressListener((FileDownloaderBinder) mBinder); - Pair putResult = mPendingDownloads.putIfAbsent(user.getAccountName(), - file.getRemotePath(), - newDownload); - if (putResult != null) { - String downloadKey = putResult.first; - requestedDownloads.add(downloadKey); - sendBroadcastNewDownload(newDownload, putResult.second); - } // else, file already in the queue of downloads; don't repeat the request - - } catch (IllegalArgumentException e) { - Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage()); - return START_NOT_STICKY; - } - - if (requestedDownloads.size() > 0) { - Message msg = mServiceHandler.obtainMessage(); - msg.arg1 = startId; - msg.obj = requestedDownloads; - mServiceHandler.sendMessage(msg); - } + DownloadType downloadType = DownloadType.DOWNLOAD; + if (intent.hasExtra(DOWNLOAD_TYPE)) { + downloadType = IntentExtensionsKt.getSerializableArgument(intent, DOWNLOAD_TYPE, DownloadType.class); + } + String activityName = intent.getStringExtra(SendShareDialog.ACTIVITY_NAME); + String packageName = intent.getStringExtra(SendShareDialog.PACKAGE_NAME); + conflictUploadId = intent.getLongExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, -1); + AbstractList requestedDownloads = new Vector(); + try { + DownloadFileOperation newDownload = new DownloadFileOperation(user, + file, + behaviour, + activityName, + packageName, + activity, + downloadType); + newDownload.addDatatransferProgressListener(this); + newDownload.addDatatransferProgressListener((FileDownloaderBinder) mBinder); + Pair putResult = mPendingDownloads.putIfAbsent(user.getAccountName(), + file.getRemotePath(), + newDownload); + if (putResult != null) { + String downloadKey = putResult.first; + requestedDownloads.add(downloadKey); + sendBroadcastNewDownload(newDownload, putResult.second); + } // else, file already in the queue of downloads; don't repeat the request + + } catch (IllegalArgumentException e) { + Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage()); } - return START_NOT_STICKY; - } - - /** - * Provides a binder object that clients can use to perform operations on the queue of downloads, - * excepting the addition of new files. - * - * Implemented to perform cancellation, pause and resume of existing downloads. - */ - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - - - /** - * Called when ALL the bound clients were onbound. - */ - @Override - public boolean onUnbind(Intent intent) { - ((FileDownloaderBinder) mBinder).clearListeners(); - return false; // not accepting rebinding (default behaviour) + if (requestedDownloads.size() > 0) { + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = startId; + msg.obj = requestedDownloads; + mServiceHandler.sendMessage(msg); + } } @Override @@ -435,8 +396,6 @@ public void handleMessage(Message msg) { } Log_OC.d(TAG, "Stopping after command with id " + msg.arg1); mService.mNotificationManager.cancel(FOREGROUND_SERVICE_ID); - mService.stopForeground(true); - mService.stopSelf(msg.arg1); }, 2000); } } @@ -463,14 +422,14 @@ private void downloadFile(String downloadKey) { Optional currentDownloadUser = accountManager.getUser(currentDownloadAccount.name); if (!currentUser.equals(currentDownloadUser)) { currentUser = currentDownloadUser; - mStorageManager = new FileDataStorageManager(currentUser.get(), getContentResolver()); + mStorageManager = new FileDataStorageManager(currentUser.get(), activity.getContentResolver()); } // else, reuse storage manager from previous operation // always get client from client manager, to get fresh credentials in case // of update OwnCloudAccount ocAccount = currentDownloadUser.get().toOwnCloudAccount(); mDownloadClient = OwnCloudClientManagerFactory.getDefaultSingleton(). - getClientFor(ocAccount, this); + getClientFor(ocAccount, activity); /// perform the download @@ -547,17 +506,16 @@ private void saveDownloadedFile() { private void notifyDownloadStart(DownloadFileOperation download) { /// create status notification with a progress bar mLastPercent = 0; - mNotificationBuilder = NotificationUtils.newNotificationBuilder(this, viewThemeUtils); + mNotificationBuilder = NotificationUtils.newNotificationBuilder(activity, viewThemeUtils); mNotificationBuilder .setSmallIcon(R.drawable.notification_icon) - .setTicker(getString(R.string.downloader_download_in_progress_ticker)) - .setContentTitle(getString(R.string.downloader_download_in_progress_ticker)) + .setTicker(activity.getString(R.string.downloader_download_in_progress_ticker)) + .setContentTitle(activity.getString(R.string.downloader_download_in_progress_ticker)) .setOngoing(true) .setProgress(100, 0, download.getSize() < 0) .setContentText( - String.format(getString(R.string.downloader_download_in_progress_content), 0, - new File(download.getSavePath()).getName()) - ); + String.format(activity.getString(R.string.downloader_download_in_progress_content), 0, + new File(download.getSavePath()).getName())); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { mNotificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD); @@ -566,20 +524,20 @@ private void notifyDownloadStart(DownloadFileOperation download) { /// includes a pending intent in the notification showing the details view of the file Intent showDetailsIntent = null; if (PreviewImageFragment.canBePreviewed(download.getFile())) { - showDetailsIntent = new Intent(this, PreviewImageActivity.class); + showDetailsIntent = new Intent(activity, PreviewImageActivity.class); } else { - showDetailsIntent = new Intent(this, FileDisplayActivity.class); + showDetailsIntent = new Intent(activity, FileDisplayActivity.class); } showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, download.getFile()); showDetailsIntent.putExtra(FileActivity.EXTRA_USER, download.getUser()); showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - mNotificationBuilder.setContentIntent(PendingIntent.getActivity(this, (int) System.currentTimeMillis(), + mNotificationBuilder.setContentIntent(PendingIntent.getActivity(activity, (int) System.currentTimeMillis(), showDetailsIntent, PendingIntent.FLAG_IMMUTABLE)); if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); } if (mNotificationManager != null) { mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotificationBuilder.build()); @@ -597,11 +555,11 @@ public void onTransferProgress(long progressRate, long totalTransferredSoFar, if (percent != mLastPercent) { mNotificationBuilder.setProgress(100, percent, totalToTransfer < 0); String fileName = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1); - String text = String.format(getString(R.string.downloader_download_in_progress_content), percent, fileName); + String text = String.format(activity.getString(R.string.downloader_download_in_progress_content), percent, fileName); mNotificationBuilder.setContentText(text); if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); } if (mNotificationManager != null) { @@ -623,7 +581,7 @@ public void onTransferProgress(long progressRate, long totalTransferredSoFar, private void notifyDownloadResult(DownloadFileOperation download, RemoteOperationResult downloadResult) { if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); } if (!downloadResult.isCancelled()) { @@ -642,8 +600,8 @@ private void notifyDownloadResult(DownloadFileOperation download, R.string.downloader_download_failed_credentials_error : tickerId; mNotificationBuilder - .setTicker(getString(tickerId)) - .setContentTitle(getString(tickerId)) + .setTicker(activity.getString(tickerId)) + .setContentTitle(activity.getString(tickerId)) .setAutoCancel(true) .setOngoing(false) .setProgress(0, 0, false); @@ -654,12 +612,12 @@ private void notifyDownloadResult(DownloadFileOperation download, } else { // TODO put something smart in showDetailsIntent Intent showDetailsIntent = new Intent(); - mNotificationBuilder.setContentIntent(PendingIntent.getActivity(this, (int) System.currentTimeMillis(), + mNotificationBuilder.setContentIntent(PendingIntent.getActivity(activity, (int) System.currentTimeMillis(), showDetailsIntent, PendingIntent.FLAG_IMMUTABLE)); } mNotificationBuilder.setContentText(ErrorMessageAdapter.getErrorCauseMessage(downloadResult, - download, getResources())); + download, activity.getResources())); if (mNotificationManager != null) { mNotificationManager.notify((new SecureRandom()).nextInt(), mNotificationBuilder.build()); @@ -676,7 +634,7 @@ private void notifyDownloadResult(DownloadFileOperation download, private void configureUpdateCredentialsNotification(User user) { // let the user update credentials with one click - Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class); + Intent updateAccountCredentials = new Intent(activity, AuthenticatorActivity.class); updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()); updateAccountCredentials.putExtra( AuthenticatorActivity.EXTRA_ACTION, @@ -686,7 +644,7 @@ private void configureUpdateCredentialsNotification(User user) { updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND); mNotificationBuilder.setContentIntent( - PendingIntent.getActivity(this, + PendingIntent.getActivity(activity, (int) System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE) @@ -717,7 +675,7 @@ private void sendBroadcastDownloadFinished( if (unlinkedFromRemotePath != null) { end.putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath); } - end.setPackage(getPackageName()); + end.setPackage(activity.getPackageName()); localBroadcastManager.sendBroadcast(end); } @@ -734,7 +692,7 @@ private void sendBroadcastNewDownload(DownloadFileOperation download, added.putExtra(ACCOUNT_NAME, download.getUser().getAccountName()); added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath()); added.putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath); - added.setPackage(getPackageName()); + added.setPackage(activity.getPackageName()); localBroadcastManager.sendBroadcast(added); } From 1b8e25b77bd8d614a3fe953f384d4539dd017ac9 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Dec 2023 14:14:32 +0100 Subject: [PATCH 002/189] Solve git conflicts Signed-off-by: alperozturk --- app/src/main/AndroidManifest.xml | 4 - .../nextcloud/client/di/ComponentsModule.java | 2 + ...wnloadWorker.kt => FilesDownloadWorker.kt} | 33 +++++-- .../client/jobs/BackgroundJobFactory.kt | 13 +++ .../client/jobs/BackgroundJobManager.kt | 11 +++ .../client/jobs/BackgroundJobManagerImpl.kt | 30 +++++++ .../nextcloud/client/jobs/FilesExportWork.kt | 3 +- .../files/services/FileDownloader.java | 87 ++++++++----------- .../operations/SynchronizeFileOperation.java | 6 +- .../ui/activity/ConflictsResolveActivity.kt | 3 +- .../android/ui/activity/FileActivity.java | 3 +- .../ui/preview/PreviewImageActivity.java | 2 +- .../ui/preview/PreviewMediaFragment.java | 2 +- 13 files changed, 128 insertions(+), 71 deletions(-) rename app/src/main/java/com/nextcloud/client/files/downloader/{DownloadWorker.kt => FilesDownloadWorker.kt} (52%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 627b1e8a22ee..3d9cb464745e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -393,10 +393,6 @@ - createCalendarImportWork(context, workerParameters) FilesExportWork::class -> createFilesExportWork(context, workerParameters) FilesUploadWorker::class -> createFilesUploadWorker(context, workerParameters) + FilesDownloadWorker::class -> createFilesDownloadWorker(context, workerParameters) GeneratePdfFromImagesWork::class -> createPDFGenerateWork(context, workerParameters) HealthStatusWork::class -> createHealthStatusWork(context, workerParameters) TestJob::class -> createTestJob(context, workerParameters) @@ -253,6 +255,17 @@ class BackgroundJobFactory @Inject constructor( ) } + private fun createFilesDownloadWorker(context: Context, params: WorkerParameters): FilesDownloadWorker { + return FilesDownloadWorker( + viewThemeUtils.get(), + accountManager, + uploadsStorageManager, + localBroadcastManager.get(), + context, + params + ) + } + private fun createPDFGenerateWork(context: Context, params: WorkerParameters): GeneratePdfFromImagesWork { return GeneratePdfFromImagesWork( appContext = context, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 750e967ccea9..fbcc04922e17 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -23,6 +23,7 @@ import androidx.lifecycle.LiveData import androidx.work.ListenableWorker import com.nextcloud.client.account.User import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.operations.DownloadType /** * This interface allows to control, schedule and monitor all application @@ -144,6 +145,16 @@ interface BackgroundJobManager { fun getFileUploads(user: User): LiveData> fun cancelFilesUploadJob(user: User) + fun startFilesDownloadJob( + user: User, + ocFile: OCFile, + behaviour: String, + downloadType: DownloadType, + activityName: String, + packageName: String, + conflictUploadId: Long + ) + fun startPdfGenerateAndUploadWork(user: User, uploadFolder: String, imagePaths: List, pdfPath: String) fun scheduleTestJob() diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 68bf01dcda36..d291189269de 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -38,8 +38,11 @@ import com.nextcloud.client.account.User import com.nextcloud.client.core.Clock import com.nextcloud.client.di.Injectable import com.nextcloud.client.documentscan.GeneratePdfFromImagesWork +import com.nextcloud.client.files.downloader.FilesDownloadWorker import com.nextcloud.client.preferences.AppPreferences import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.operations.DownloadType +import java.io.File import java.util.Date import java.util.UUID import java.util.concurrent.TimeUnit @@ -83,6 +86,7 @@ internal class BackgroundJobManagerImpl( const val JOB_NOTIFICATION = "notification" const val JOB_ACCOUNT_REMOVAL = "account_removal" const val JOB_FILES_UPLOAD = "files_upload" + const val JOB_FILES_DOWNLOAD = "files_download" const val JOB_PDF_GENERATION = "pdf_generation" const val JOB_IMMEDIATE_CALENDAR_BACKUP = "immediate_calendar_backup" const val JOB_IMMEDIATE_FILES_EXPORT = "immediate_files_export" @@ -505,6 +509,32 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_FILES_UPLOAD + user.accountName, ExistingWorkPolicy.KEEP, request) } + override fun startFilesDownloadJob( + user: User, + ocFile: OCFile, + behaviour: String, + downloadType: DownloadType, + activityName: String, + packageName: String, + conflictUploadId: Long + ) { + val data = workDataOf( + FilesDownloadWorker.USER to user, + FilesDownloadWorker.FILE to ocFile, + FilesDownloadWorker.BEHAVIOUR to behaviour, + FilesDownloadWorker.DOWNLOAD_TYPE to downloadType, + FilesDownloadWorker.ACTIVITY_NAME to activityName, + FilesDownloadWorker.PACKAGE_NAME to packageName, + FilesDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId, + ) + + val request = oneTimeRequestBuilder(FilesDownloadWorker::class, JOB_FILES_DOWNLOAD, user) + .setInputData(data) + .build() + + workManager.enqueueUniqueWork(JOB_FILES_DOWNLOAD + user.accountName, ExistingWorkPolicy.REPLACE, request) + } + override fun getFileUploads(user: User): LiveData> { val workInfo = workManager.getWorkInfosByTagLiveData(formatNameTag(JOB_FILES_UPLOAD, user)) return workInfo.map { it -> it.map { fromWorkInfo(it) ?: JobInfo() } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt index d8a417513be0..cb8172655ccf 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt @@ -118,7 +118,8 @@ class FilesExportWork( i.putExtra(SendShareDialog.PACKAGE_NAME, "") i.putExtra(SendShareDialog.ACTIVITY_NAME, "") i.putExtra(FileDownloader.DOWNLOAD_TYPE, DownloadType.EXPORT) - appContext.startService(i) + + FileDownloader(i) } private fun showErrorNotification(successfulExports: Int) { diff --git a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java index d0db5d7761ad..a528d479ffe1 100644 --- a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java +++ b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java @@ -23,11 +23,10 @@ import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.OnAccountsUpdateListener; -import android.app.Activity; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; -import android.app.Service; +import android.content.Context; import android.content.Intent; import android.graphics.BitmapFactory; import android.os.Binder; @@ -42,13 +41,13 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.files.downloader.DownloadTask; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.java.util.Optional; -import com.nextcloud.utils.ForegroundServiceHelper; import com.nextcloud.utils.extensions.IntentExtensionsKt; +import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.authentication.AuthenticatorActivity; import com.owncloud.android.datamodel.FileDataStorageManager; -import com.owncloud.android.datamodel.ForegroundServiceType; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.UploadsStorageManager; import com.owncloud.android.lib.common.OwnCloudAccount; @@ -86,16 +85,17 @@ import androidx.core.app.NotificationCompat; import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import dagger.android.AndroidInjection; +import androidx.work.OneTimeWorkRequest; +import androidx.work.WorkManager; +import androidx.work.WorkRequest; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import static android.content.Context.NOTIFICATION_SERVICE; public class FileDownloader implements OnDatatransferProgressListener, OnAccountsUpdateListener { - private final Activity activity; + private final Context context = MainApp.getAppContext(); private final Intent intent; - private final int startId; public static final String EXTRA_USER = "USER"; public static final String EXTRA_FILE = "FILE"; @@ -146,25 +146,21 @@ public static String getDownloadFinishMessage() { return FileDownloader.class.getName() + DOWNLOAD_FINISH_MESSAGE; } - public FileDownloader(Activity activity, Intent intent, int startId) { - this.activity = activity; + public FileDownloader(Intent intent) { this.intent = intent; - this.startId = startId; - - AndroidInjection.inject(activity); Log_OC.d(TAG, "Creating service"); - mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); + mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); HandlerThread thread = new HandlerThread("FileDownloaderThread", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper, this); mBinder = new FileDownloaderBinder(); - NotificationCompat.Builder builder = NotificationUtils.newNotificationBuilder(activity, viewThemeUtils).setContentTitle( - activity.getResources().getString(R.string.app_name)) - .setContentText(activity.getResources().getString(R.string.foreground_service_download)) + NotificationCompat.Builder builder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).setContentTitle( + context.getResources().getString(R.string.app_name)) + .setContentText(context.getResources().getString(R.string.foreground_service_download)) .setSmallIcon(R.drawable.notification_icon) - .setLargeIcon(BitmapFactory.decodeResource(activity.getResources(), R.drawable.notification_icon)); + .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.notification_icon)); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { @@ -174,11 +170,10 @@ public FileDownloader(Activity activity, Intent intent, int startId) { mNotification = builder.build(); // add AccountsUpdatedListener - AccountManager am = AccountManager.get(activity); + AccountManager am = AccountManager.get(context); am.addOnAccountsUpdatedListener(this, null, false); } - @Override protected void finalize() throws Throwable { Log_OC.v(TAG, "Destroying service"); @@ -189,7 +184,7 @@ protected void finalize() throws Throwable { mNotificationManager = null; // remove AccountsUpdatedListener - AccountManager am = AccountManager.get(activity); + AccountManager am = AccountManager.get(context); am.removeOnAccountsUpdatedListener(this); super.finalize(); } @@ -213,7 +208,7 @@ public void download() { behaviour, activityName, packageName, - activity, + context, downloadType); newDownload.addDatatransferProgressListener(this); newDownload.addDatatransferProgressListener((FileDownloaderBinder) mBinder); @@ -232,7 +227,7 @@ public void download() { if (requestedDownloads.size() > 0) { Message msg = mServiceHandler.obtainMessage(); - msg.arg1 = startId; + // msg.arg1 = startId; msg.obj = requestedDownloads; mServiceHandler.sendMessage(msg); } @@ -247,7 +242,6 @@ public void onAccountsUpdated(Account[] accounts) { // The rest of downloads are cancelled when they try to start } - /** * Binder to let client components to perform operations on the queue of downloads. *

@@ -296,11 +290,6 @@ public void cancel(String accountName) { cancelPendingDownloads(accountName); } - public void clearListeners() { - mBoundListeners.clear(); - } - - /** * Returns True when the file described by 'file' in the ownCloud account 'account' * is downloading or waiting to download. @@ -422,14 +411,14 @@ private void downloadFile(String downloadKey) { Optional currentDownloadUser = accountManager.getUser(currentDownloadAccount.name); if (!currentUser.equals(currentDownloadUser)) { currentUser = currentDownloadUser; - mStorageManager = new FileDataStorageManager(currentUser.get(), activity.getContentResolver()); + mStorageManager = new FileDataStorageManager(currentUser.get(), context.getContentResolver()); } // else, reuse storage manager from previous operation // always get client from client manager, to get fresh credentials in case // of update OwnCloudAccount ocAccount = currentDownloadUser.get().toOwnCloudAccount(); mDownloadClient = OwnCloudClientManagerFactory.getDefaultSingleton(). - getClientFor(ocAccount, activity); + getClientFor(ocAccount, context); /// perform the download @@ -506,15 +495,15 @@ private void saveDownloadedFile() { private void notifyDownloadStart(DownloadFileOperation download) { /// create status notification with a progress bar mLastPercent = 0; - mNotificationBuilder = NotificationUtils.newNotificationBuilder(activity, viewThemeUtils); + mNotificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils); mNotificationBuilder .setSmallIcon(R.drawable.notification_icon) - .setTicker(activity.getString(R.string.downloader_download_in_progress_ticker)) - .setContentTitle(activity.getString(R.string.downloader_download_in_progress_ticker)) + .setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) + .setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) .setOngoing(true) .setProgress(100, 0, download.getSize() < 0) .setContentText( - String.format(activity.getString(R.string.downloader_download_in_progress_content), 0, + String.format(context.getString(R.string.downloader_download_in_progress_content), 0, new File(download.getSavePath()).getName())); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { @@ -524,20 +513,20 @@ private void notifyDownloadStart(DownloadFileOperation download) { /// includes a pending intent in the notification showing the details view of the file Intent showDetailsIntent = null; if (PreviewImageFragment.canBePreviewed(download.getFile())) { - showDetailsIntent = new Intent(activity, PreviewImageActivity.class); + showDetailsIntent = new Intent(context, PreviewImageActivity.class); } else { - showDetailsIntent = new Intent(activity, FileDisplayActivity.class); + showDetailsIntent = new Intent(context, FileDisplayActivity.class); } showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, download.getFile()); showDetailsIntent.putExtra(FileActivity.EXTRA_USER, download.getUser()); showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - mNotificationBuilder.setContentIntent(PendingIntent.getActivity(activity, (int) System.currentTimeMillis(), + mNotificationBuilder.setContentIntent(PendingIntent.getActivity(context, (int) System.currentTimeMillis(), showDetailsIntent, PendingIntent.FLAG_IMMUTABLE)); if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); + mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); } if (mNotificationManager != null) { mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotificationBuilder.build()); @@ -555,11 +544,11 @@ public void onTransferProgress(long progressRate, long totalTransferredSoFar, if (percent != mLastPercent) { mNotificationBuilder.setProgress(100, percent, totalToTransfer < 0); String fileName = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1); - String text = String.format(activity.getString(R.string.downloader_download_in_progress_content), percent, fileName); + String text = String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName); mNotificationBuilder.setContentText(text); if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); + mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); } if (mNotificationManager != null) { @@ -581,7 +570,7 @@ public void onTransferProgress(long progressRate, long totalTransferredSoFar, private void notifyDownloadResult(DownloadFileOperation download, RemoteOperationResult downloadResult) { if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); + mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); } if (!downloadResult.isCancelled()) { @@ -600,8 +589,8 @@ private void notifyDownloadResult(DownloadFileOperation download, R.string.downloader_download_failed_credentials_error : tickerId; mNotificationBuilder - .setTicker(activity.getString(tickerId)) - .setContentTitle(activity.getString(tickerId)) + .setTicker(context.getString(tickerId)) + .setContentTitle(context.getString(tickerId)) .setAutoCancel(true) .setOngoing(false) .setProgress(0, 0, false); @@ -612,12 +601,12 @@ private void notifyDownloadResult(DownloadFileOperation download, } else { // TODO put something smart in showDetailsIntent Intent showDetailsIntent = new Intent(); - mNotificationBuilder.setContentIntent(PendingIntent.getActivity(activity, (int) System.currentTimeMillis(), + mNotificationBuilder.setContentIntent(PendingIntent.getActivity(context, (int) System.currentTimeMillis(), showDetailsIntent, PendingIntent.FLAG_IMMUTABLE)); } mNotificationBuilder.setContentText(ErrorMessageAdapter.getErrorCauseMessage(downloadResult, - download, activity.getResources())); + download, context.getResources())); if (mNotificationManager != null) { mNotificationManager.notify((new SecureRandom()).nextInt(), mNotificationBuilder.build()); @@ -634,7 +623,7 @@ private void notifyDownloadResult(DownloadFileOperation download, private void configureUpdateCredentialsNotification(User user) { // let the user update credentials with one click - Intent updateAccountCredentials = new Intent(activity, AuthenticatorActivity.class); + Intent updateAccountCredentials = new Intent(context, AuthenticatorActivity.class); updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()); updateAccountCredentials.putExtra( AuthenticatorActivity.EXTRA_ACTION, @@ -644,7 +633,7 @@ private void configureUpdateCredentialsNotification(User user) { updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND); mNotificationBuilder.setContentIntent( - PendingIntent.getActivity(activity, + PendingIntent.getActivity(context, (int) System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE) @@ -675,7 +664,7 @@ private void sendBroadcastDownloadFinished( if (unlinkedFromRemotePath != null) { end.putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath); } - end.setPackage(activity.getPackageName()); + end.setPackage(context.getPackageName()); localBroadcastManager.sendBroadcast(end); } @@ -692,7 +681,7 @@ private void sendBroadcastNewDownload(DownloadFileOperation download, added.putExtra(ACCOUNT_NAME, download.getUser().getAccountName()); added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath()); added.putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath); - added.setPackage(activity.getPackageName()); + added.setPackage(context.getPackageName()); localBroadcastManager.sendBroadcast(added); } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java index e7e291279a8c..80c4e2411a36 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -320,12 +320,8 @@ private void requestForDownload(OCFile file) { Intent i = new Intent(mContext, FileDownloader.class); i.putExtra(FileDownloader.EXTRA_USER, mUser); i.putExtra(FileDownloader.EXTRA_FILE, file); - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - mContext.startForegroundService(i); - } else { - mContext.startService(i); - } + new FileDownloader(i); mTransferWasRequested = true; } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt index 0481a973343d..830fee88af4f 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt @@ -118,7 +118,8 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener intent.putExtra(FileDownloader.EXTRA_USER, getUser().orElseThrow { RuntimeException() }) intent.putExtra(FileDownloader.EXTRA_FILE, file) intent.putExtra(EXTRA_CONFLICT_UPLOAD_ID, conflictUploadId) - startService(intent) + + FileDownloader(intent) } else { uploadsStorageManager!!.removeUpload(upload) } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index 39ba31a2853f..27ae30f27f45 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -234,8 +234,7 @@ protected void onCreate(Bundle savedInstanceState) { mDownloadServiceConnection = newTransferenceServiceConnection(); if (mDownloadServiceConnection != null) { - bindService(new Intent(this, FileDownloader.class), mDownloadServiceConnection, - Context.BIND_AUTO_CREATE); + new FileDownloader(new Intent(this, FileDownloader.class)); } mUploadServiceConnection = newTransferenceServiceConnection(); if (mUploadServiceConnection != null) { diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 7bb7aca1dc04..1152562ae92d 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -419,7 +419,7 @@ public void requestForDownload(OCFile file, String downloadBehaviour) { if (downloadBehaviour != null) { i.putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, downloadBehaviour); } - startService(i); + new FileDownloader(i); } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index baf19af7cb3e..2b685b8a8c59 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -482,7 +482,7 @@ public void onFileActionChosen(final int itemId) { Intent i = new Intent(requireActivity(), FileDownloader.class); i.putExtra(FileDownloader.EXTRA_USER, user); i.putExtra(FileDownloader.EXTRA_FILE, getFile()); - requireActivity().startService(i); + new FileDownloader(i); } } } From f4802b9519f677c334d9c3dcdda3306a0222027c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 10:49:13 +0100 Subject: [PATCH 003/189] Implement FilesDownloadHelper Signed-off-by: alperozturk --- .../com/nextcloud/client/di/AppComponent.java | 3 + .../files/downloader/FilesDownloadHelper.kt | 63 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt diff --git a/app/src/main/java/com/nextcloud/client/di/AppComponent.java b/app/src/main/java/com/nextcloud/client/di/AppComponent.java index d47bdfdff7c8..4c677a313c6c 100644 --- a/app/src/main/java/com/nextcloud/client/di/AppComponent.java +++ b/app/src/main/java/com/nextcloud/client/di/AppComponent.java @@ -26,6 +26,7 @@ import com.nextcloud.client.appinfo.AppInfoModule; import com.nextcloud.client.database.DatabaseModule; import com.nextcloud.client.device.DeviceModule; +import com.nextcloud.client.files.downloader.FilesDownloadHelper; import com.nextcloud.client.integrations.IntegrationsModule; import com.nextcloud.client.jobs.JobsModule; import com.nextcloud.client.network.NetworkModule; @@ -71,6 +72,8 @@ public interface AppComponent { void inject(FilesUploadHelper filesUploadHelper); + void inject(FilesDownloadHelper filesDownloadHelper); + void inject(ProgressIndicator progressIndicator); @Component.Builder diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt new file mode 100644 index 000000000000..b5e316a28871 --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt @@ -0,0 +1,63 @@ +/* + * 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 . + */ + +package com.nextcloud.client.files.downloader + +import com.nextcloud.client.account.User +import com.nextcloud.client.jobs.BackgroundJobManager +import com.owncloud.android.MainApp +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.datamodel.UploadsStorageManager +import com.owncloud.android.operations.DownloadType +import javax.inject.Inject + +class FilesDownloadHelper { + + @Inject + lateinit var backgroundJobManager: BackgroundJobManager + + @Inject + lateinit var uploadsStorageManager: UploadsStorageManager + + init { + MainApp.getAppComponent().inject(this) + } + + fun downloadFile( + user: User, + ocFile: OCFile, + behaviour: String, + downloadType: DownloadType, + activityName: String, + packageName: String, + conflictUploadId: Long + ) { + backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + behaviour, + downloadType, + activityName, + packageName, + conflictUploadId + ) + } +} From a2afffc667589b451d46bc9714d2ada8e0ef25d9 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 11:33:05 +0100 Subject: [PATCH 004/189] Implement FilesDownloadWorker Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 489 +++++++++++++++++- .../files/services/FileDownloader.java | 9 +- 2 files changed, 489 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index 52119e015c64..90b81bd618b7 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -21,24 +21,71 @@ package com.nextcloud.client.files.downloader +import android.accounts.Account +import android.accounts.AccountManager +import android.accounts.OnAccountsUpdateListener +import android.app.Notification +import android.app.NotificationManager +import android.app.PendingIntent import android.content.Context +import android.content.Intent +import android.graphics.BitmapFactory +import android.os.Binder +import android.os.Build +import android.os.Handler +import android.os.IBinder +import android.os.Looper +import android.os.Message +import android.util.Pair +import androidx.core.app.NotificationCompat import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters +import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.java.util.Optional +import com.owncloud.android.R +import com.owncloud.android.authentication.AuthenticatorActivity +import com.owncloud.android.datamodel.FileDataStorageManager +import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager +import com.owncloud.android.files.services.FileDownloader +import com.owncloud.android.files.services.IndexedForest +import com.owncloud.android.lib.common.OwnCloudClient +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory +import com.owncloud.android.lib.common.network.OnDatatransferProgressListener +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode +import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.resources.files.FileUtils +import com.owncloud.android.operations.DownloadFileOperation +import com.owncloud.android.operations.DownloadType +import com.owncloud.android.ui.activity.FileActivity +import com.owncloud.android.ui.activity.FileDisplayActivity +import com.owncloud.android.ui.dialog.SendShareDialog +import com.owncloud.android.ui.fragment.OCFileListFragment +import com.owncloud.android.ui.notifications.NotificationUtils +import com.owncloud.android.ui.preview.PreviewImageActivity +import com.owncloud.android.ui.preview.PreviewImageFragment +import com.owncloud.android.utils.ErrorMessageAdapter +import com.owncloud.android.utils.MimeTypeUtil import com.owncloud.android.utils.theme.ViewThemeUtils +import java.io.File +import java.security.SecureRandom +import java.util.AbstractList +import java.util.Vector class FilesDownloadWorker( private val viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, private val uploadsStorageManager: UploadsStorageManager, private var localBroadcastManager: LocalBroadcastManager, - context: Context, + private val context: Context, params: WorkerParameters, -) : Worker(context, params) { +) : Worker(context, params), OnAccountsUpdateListener, OnDatatransferProgressListener { companion object { + private val TAG = FilesDownloadWorker::class.java.simpleName const val USER = "USER" const val FILE = "FILE" const val BEHAVIOUR = "BEHAVIOUR" @@ -48,11 +95,449 @@ class FilesDownloadWorker( const val CONFLICT_UPLOAD_ID = "CONFLICT_UPLOAD_ID" } + private var notification: Notification? = null + private var currentDownload: DownloadFileOperation? = null + private var conflictUploadId: Long? = null + private var lastPercent = 0 + private var notificationBuilder: NotificationCompat.Builder? = null + private var notificationManager: NotificationManager? = null + private val pendingDownloads = IndexedForest() + private var downloadBinder: IBinder? = null + private var currentUser = Optional.empty() + private val workerHandler: WorkerHandler? = null + private var startedDownload = false + private var storageManager: FileDataStorageManager? = null + private var downloadClient: OwnCloudClient? = null + override fun doWork(): Result { return try { + conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long + val user = inputData.keyValueMap[USER] as User + val file = inputData.keyValueMap[FILE] as OCFile + val downloadType = inputData.keyValueMap[DOWNLOAD_TYPE] as DownloadType + val behaviour = inputData.keyValueMap[BEHAVIOUR] as String + val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String + val packageName = inputData.keyValueMap[PACKAGE_NAME] as String + downloadBinder = FileDownloaderBinder() + + showDownloadingFilesNotification() + addAccountUpdateListener() + download(user, file, behaviour, downloadType, activityName, packageName) + Result.success() } catch (t: Throwable) { Result.failure() } } + + private fun download( + user: User, + file: OCFile, + behaviour: String, + downloadType: DownloadType, + activityName: String, + packageName: String, + ) { + val requestedDownloads: AbstractList = Vector() + try { + val newDownload = DownloadFileOperation( + user, + file, + behaviour, + activityName, + packageName, + context, + downloadType + ) + newDownload.addDatatransferProgressListener(this) + newDownload.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder?) + val putResult: Pair = pendingDownloads.putIfAbsent( + user.accountName, + file.remotePath, + newDownload + ) + + val downloadKey = putResult.first + requestedDownloads.add(downloadKey) + sendBroadcastNewDownload(newDownload, putResult.second) + } catch (e: IllegalArgumentException) { + Log_OC.e(TAG, "Not enough information provided in intent: " + e.message) + } + + if (requestedDownloads.size > 0) { + val msg: Message? = workerHandler?.obtainMessage() + // msg.arg1 = startId; + msg?.obj = requestedDownloads + + msg?.let { + workerHandler?.sendMessage(msg) + } + } + } + + private fun downloadFile(downloadKey: String) { + startedDownload = true + currentDownload = pendingDownloads.get(downloadKey) + if (currentDownload != null) { + if (accountManager.exists(currentDownload?.user?.toPlatformAccount())) { + notifyDownloadStart(currentDownload!!) + var downloadResult: RemoteOperationResult<*>? = null + try { + /// prepare client object to send the request to the ownCloud server + val currentDownloadAccount: Account? = currentDownload?.user?.toPlatformAccount() + val currentDownloadUser = accountManager.getUser(currentDownloadAccount?.name) + if (currentUser != currentDownloadUser) { + currentUser = currentDownloadUser + storageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) + } // else, reuse storage manager from previous operation + + val ocAccount = currentDownloadUser.get().toOwnCloudAccount() + downloadClient = + OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, context) + + downloadResult = currentDownload!!.execute(downloadClient) + if (downloadResult?.isSuccess == true && currentDownload?.downloadType === DownloadType.DOWNLOAD) { + saveDownloadedFile() + } + } catch (e: Exception) { + Log_OC.e(TAG, "Error downloading", e) + downloadResult = RemoteOperationResult(e) + } finally { + val removeResult: Pair = pendingDownloads.removePayload( + currentDownload?.user?.accountName, currentDownload?.remotePath + ) + + if (downloadResult == null) { + downloadResult = RemoteOperationResult(RuntimeException("Error downloading…")) + } + + currentDownload?.let { + notifyDownloadResult(it, downloadResult) + sendBroadcastDownloadFinished(it, downloadResult, removeResult.second) + } + } + } else { + cancelPendingDownloads(currentDownload?.user?.accountName) + } + } + } + + private fun saveDownloadedFile() { + var file: OCFile? = currentDownload?.file?.fileId?.let { storageManager?.getFileById(it) } + if (file == null) { + // try to get file via path, needed for overwriting existing files on conflict dialog + file = storageManager?.getFileByDecryptedRemotePath(currentDownload?.file?.remotePath) + } + if (file == null) { + Log_OC.e(this, "Could not save " + currentDownload?.file?.remotePath) + return + } + val syncDate = System.currentTimeMillis() + file.lastSyncDateForProperties = syncDate + file.lastSyncDateForData = syncDate + file.isUpdateThumbnailNeeded = true + file.modificationTimestamp = currentDownload?.modificationTimestamp ?: 0L + file.modificationTimestampAtLastSyncForData = currentDownload?.modificationTimestamp ?: 0L + file.etag = currentDownload?.etag + file.mimeType = currentDownload?.mimeType + file.storagePath = currentDownload?.savePath + file.fileLength = File(currentDownload?.getSavePath()).length() + file.remoteId = currentDownload?.file?.remoteId + storageManager?.saveFile(file) + + if (MimeTypeUtil.isMedia(currentDownload?.mimeType)) { + FileDataStorageManager.triggerMediaScan(file.storagePath, file) + } + + storageManager?.saveConflict(file, null) + } + + private fun sendBroadcastDownloadFinished( + download: DownloadFileOperation, + downloadResult: RemoteOperationResult<*>, + unlinkedFromRemotePath: String? + ) { + val end = Intent(FileDownloader.getDownloadFinishMessage()) + end.putExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) + end.putExtra(FileDownloader.ACCOUNT_NAME, download.user.accountName) + end.putExtra(FileDownloader.EXTRA_REMOTE_PATH, download.remotePath) + end.putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) + end.putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) + end.putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) + if (unlinkedFromRemotePath != null) { + end.putExtra(FileDownloader.EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) + } + end.setPackage(context.packageName) + localBroadcastManager.sendBroadcast(end) + } + + private fun notifyDownloadResult( + download: DownloadFileOperation, + downloadResult: RemoteOperationResult<*> + ) { + if (notificationManager == null) { + notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + } + + if (!downloadResult.isCancelled) { + if (downloadResult.isSuccess) { + if (conflictUploadId!! > 0) { + uploadsStorageManager.removeUpload(conflictUploadId!!) + } + // Dont show notification except an error has occured. + return + } + var tickerId = + if (downloadResult.isSuccess) R.string.downloader_download_succeeded_ticker else R.string.downloader_download_failed_ticker + val needsToUpdateCredentials = ResultCode.UNAUTHORIZED == downloadResult.code + tickerId = if (needsToUpdateCredentials) R.string.downloader_download_failed_credentials_error else tickerId + + notificationBuilder + ?.setTicker(context.getString(tickerId)) + ?.setContentTitle(context.getString(tickerId)) + ?.setAutoCancel(true) + ?.setOngoing(false) + ?.setProgress(0, 0, false) + + if (needsToUpdateCredentials) { + configureUpdateCredentialsNotification(download.user) + } else { + // TODO put something smart in showDetailsIntent + val showDetailsIntent = Intent() + notificationBuilder?.setContentIntent( + PendingIntent.getActivity( + context, System.currentTimeMillis().toInt(), + showDetailsIntent, PendingIntent.FLAG_IMMUTABLE + ) + ) + } + + notificationBuilder?.setContentText( + ErrorMessageAdapter.getErrorCauseMessage( + downloadResult, + download, context.resources + ) + ) + + if (notificationManager != null) { + notificationManager?.notify(SecureRandom().nextInt(), notificationBuilder?.build()) + if (downloadResult.isSuccess) { + NotificationUtils.cancelWithDelay( + notificationManager, + R.string.downloader_download_succeeded_ticker, 2000 + ) + } + } + } + } + + private fun configureUpdateCredentialsNotification(user: User) { + val updateAccountCredentials = Intent(context, AuthenticatorActivity::class.java) + updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) + updateAccountCredentials.putExtra( + AuthenticatorActivity.EXTRA_ACTION, + AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN + ) + updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND) + notificationBuilder?.setContentIntent( + PendingIntent.getActivity( + context, System.currentTimeMillis().toInt(), + updateAccountCredentials, + PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE + ) + ) + } + + private fun notifyDownloadStart(download: DownloadFileOperation) { + lastPercent = 0 + notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) + .setSmallIcon(R.drawable.notification_icon) + .setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) + .setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) + .setOngoing(true) + .setProgress(100, 0, download.size < 0) + .setContentText( + String.format( + context.getString(R.string.downloader_download_in_progress_content), 0, + File(download.savePath).name + ) + ) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationBuilder?.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + } + + /// includes a pending intent in the notification showing the details view of the file + var showDetailsIntent: Intent? = null + showDetailsIntent = if (PreviewImageFragment.canBePreviewed(download.file)) { + Intent(context, PreviewImageActivity::class.java) + } else { + Intent(context, FileDisplayActivity::class.java) + } + showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, download.file) + showDetailsIntent.putExtra(FileActivity.EXTRA_USER, download.user) + showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + notificationBuilder?.setContentIntent( + PendingIntent.getActivity( + context, System.currentTimeMillis().toInt(), + showDetailsIntent, PendingIntent.FLAG_IMMUTABLE + ) + ) + + if (notificationManager == null) { + notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + } + if (notificationManager != null) { + notificationManager?.notify(R.string.downloader_download_in_progress_ticker, notificationBuilder?.build()) + } + } + + private fun showDownloadingFilesNotification() { + val builder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) + .setContentTitle(context.resources.getString(R.string.app_name)) + .setContentText(context.resources.getString(R.string.foreground_service_download)) + .setSmallIcon(R.drawable.notification_icon) + .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) + + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + builder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + } + + notification = builder.build() + } + + private fun addAccountUpdateListener() { + val am = AccountManager.get(context) + am.addOnAccountsUpdatedListener(this, null, false) + } + + private fun cancelPendingDownloads(accountName: String?) { + pendingDownloads.remove(accountName) + } + + private fun sendBroadcastNewDownload( + download: DownloadFileOperation, + linkedToRemotePath: String + ) { + val added = Intent(FileDownloader.getDownloadAddedMessage()) + added.putExtra(FileDownloader.ACCOUNT_NAME, download.user.accountName) + added.putExtra(FileDownloader.EXTRA_REMOTE_PATH, download.remotePath) + added.putExtra(FileDownloader.EXTRA_LINKED_TO_PATH, linkedToRemotePath) + added.setPackage(context.packageName) + localBroadcastManager.sendBroadcast(added) + } + + override fun onAccountsUpdated(accounts: Array?) { + if (currentDownload != null && !accountManager.exists(currentDownload?.user?.toPlatformAccount())) { + currentDownload?.cancel() + } + } + + override fun onTransferProgress( + progressRate: Long, + totalTransferredSoFar: Long, + totalToTransfer: Long, + filePath: String + ) { + val percent: Int = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt() + if (percent != lastPercent) { + notificationBuilder?.setProgress(100, percent, totalToTransfer < 0) + val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) + val text = + String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) + notificationBuilder?.setContentText(text) + + if (notificationManager == null) { + notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + } + if (notificationManager != null) { + notificationManager?.notify( + R.string.downloader_download_in_progress_ticker, + notificationBuilder?.build() + ) + } + } + lastPercent = percent + } + + inner class FileDownloaderBinder : Binder(), OnDatatransferProgressListener { + /** + * Map of listeners that will be reported about progress of downloads from a + * [FileDownloaderBinder] + * instance. + */ + private val mBoundListeners: MutableMap = HashMap() + + /** + * Cancels a pending or current download of a remote file. + * + * @param account ownCloud account where the remote file is stored. + * @param file A file in the queue of pending downloads + */ + fun cancel(account: Account, file: OCFile) { + val removeResult: Pair = + pendingDownloads.remove(account.name, file.remotePath) + val download = removeResult.first + if (download != null) { + download.cancel() + } else { + if (currentDownload != null && currentUser?.isPresent == true && + currentDownload?.remotePath?.startsWith(file.remotePath) == true && account.name == currentUser.get()?.accountName + ) { + currentDownload?.cancel() + } + } + } + + /** + * Cancels all the downloads for an account + */ + fun cancel(accountName: String?) { + if (currentDownload != null && currentDownload?.user?.nameEquals(accountName) == true) { + currentDownload?.cancel() + } + + cancelPendingDownloads(accountName) + } + + fun isDownloading(user: User?, file: OCFile?): Boolean { + return user != null && file != null && pendingDownloads.contains(user.accountName, file.remotePath) + } + + override fun onTransferProgress( + progressRate: Long, totalTransferredSoFar: Long, + totalToTransfer: Long, fileName: String + ) { + val boundListener = mBoundListeners[currentDownload?.file?.fileId] + boundListener?.onTransferProgress( + progressRate, totalTransferredSoFar, + totalToTransfer, fileName + ) + } + } + + private class WorkerHandler(looper: Looper, private val worker: FilesDownloadWorker) : Handler(looper) { + override fun handleMessage(msg: Message) { + val requestedDownloads = msg.obj as AbstractList + + if (msg.obj != null) { + val it: Iterator = requestedDownloads.iterator() + while (it.hasNext()) { + val next = it.next() + worker.downloadFile(next) + } + } + + worker.startedDownload = false + + Handler(Looper.getMainLooper()).postDelayed({ + if (!worker.startedDownload) { + worker.notificationManager?.cancel(R.string.downloader_download_in_progress_ticker) + } + Log_OC.d(TAG, "Stopping after command with id " + msg.arg1) + }, 2000) + } + } } diff --git a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java index a528d479ffe1..6a88b168f4fd 100644 --- a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java +++ b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java @@ -247,7 +247,7 @@ public void onAccountsUpdated(Account[] accounts) { *

* It provides by itself the available operations. */ - public class FileDownloaderBinder extends Binder implements OnDatatransferProgressListener { + public class FileDownloaderBinder2 extends Binder implements OnDatatransferProgressListener { /** * Map of listeners that will be reported about progress of downloads from a @@ -390,12 +390,7 @@ public void handleMessage(Message msg) { } - /** - * Core download method: requests a file to download and stores it. - * - * @param downloadKey Key to access the download to perform, contained in mPendingDownloads - */ - private void downloadFile(String downloadKey) { + void downloadFile(String downloadKey) { mStartedDownload = true; mCurrentDownload = mPendingDownloads.get(downloadKey); From 2a00392ff51c6afd0ff4bd5b60f2475951195bf2 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 11:37:42 +0100 Subject: [PATCH 005/189] Implement FilesDownloadWorker Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 33 +++++++++++++------ .../files/services/FileDownloader.java | 6 ++-- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index 90b81bd618b7..791e03b31cb0 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -49,7 +49,6 @@ import com.owncloud.android.authentication.AuthenticatorActivity import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager -import com.owncloud.android.files.services.FileDownloader import com.owncloud.android.files.services.IndexedForest import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.OwnCloudClientManagerFactory @@ -93,6 +92,12 @@ class FilesDownloadWorker( const val ACTIVITY_NAME = "ACTIVITY_NAME" const val PACKAGE_NAME = "PACKAGE_NAME" const val CONFLICT_UPLOAD_ID = "CONFLICT_UPLOAD_ID" + const val EXTRA_USER = "USER" + const val EXTRA_FILE = "FILE" + const val EXTRA_DOWNLOAD_RESULT = "RESULT" + const val EXTRA_REMOTE_PATH = "REMOTE_PATH" + const val EXTRA_LINKED_TO_PATH = "LINKED_TO" + const val ACCOUNT_NAME = "ACCOUNT_NAME" } private var notification: Notification? = null @@ -257,15 +262,15 @@ class FilesDownloadWorker( downloadResult: RemoteOperationResult<*>, unlinkedFromRemotePath: String? ) { - val end = Intent(FileDownloader.getDownloadFinishMessage()) - end.putExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) - end.putExtra(FileDownloader.ACCOUNT_NAME, download.user.accountName) - end.putExtra(FileDownloader.EXTRA_REMOTE_PATH, download.remotePath) + val end = Intent(getDownloadFinishMessage()) + end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) + end.putExtra(ACCOUNT_NAME, download.user.accountName) + end.putExtra(EXTRA_REMOTE_PATH, download.remotePath) end.putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) end.putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) end.putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) if (unlinkedFromRemotePath != null) { - end.putExtra(FileDownloader.EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) + end.putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) } end.setPackage(context.packageName) localBroadcastManager.sendBroadcast(end) @@ -417,14 +422,22 @@ class FilesDownloadWorker( pendingDownloads.remove(accountName) } + private fun getDownloadAddedMessage(): String { + return FilesDownloadWorker::class.java.name + "DOWNLOAD_ADDED" + } + + private fun getDownloadFinishMessage(): String { + return FilesDownloadWorker::class.java.name + "DOWNLOAD_FINISH" + } + private fun sendBroadcastNewDownload( download: DownloadFileOperation, linkedToRemotePath: String ) { - val added = Intent(FileDownloader.getDownloadAddedMessage()) - added.putExtra(FileDownloader.ACCOUNT_NAME, download.user.accountName) - added.putExtra(FileDownloader.EXTRA_REMOTE_PATH, download.remotePath) - added.putExtra(FileDownloader.EXTRA_LINKED_TO_PATH, linkedToRemotePath) + val added = Intent(getDownloadAddedMessage()) + added.putExtra(ACCOUNT_NAME, download.user.accountName) + added.putExtra(EXTRA_REMOTE_PATH, download.remotePath) + added.putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath) added.setPackage(context.packageName) localBroadcastManager.sendBroadcast(added) } diff --git a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java index 6a88b168f4fd..b537db5fbf9d 100644 --- a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java +++ b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java @@ -97,11 +97,11 @@ public class FileDownloader implements OnDatatransferProgressListener, OnAccount private final Context context = MainApp.getAppContext(); private final Intent intent; - public static final String EXTRA_USER = "USER"; - public static final String EXTRA_FILE = "FILE"; - private static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED"; private static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH"; + + public static final String EXTRA_USER = "USER"; + public static final String EXTRA_FILE = "FILE"; public static final String EXTRA_DOWNLOAD_RESULT = "RESULT"; public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; public static final String EXTRA_LINKED_TO_PATH = "LINKED_TO"; From fe11d64fb3954bdcb5e871a06573e46b43b4f328 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 11:45:26 +0100 Subject: [PATCH 006/189] Refactor FilesDownloadWorker Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 104 ++++++++++-------- 1 file changed, 59 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index 791e03b31cb0..03e114612504 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -50,6 +50,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.files.services.IndexedForest +import com.owncloud.android.lib.common.OwnCloudAccount import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.OwnCloudClientManagerFactory import com.owncloud.android.lib.common.network.OnDatatransferProgressListener @@ -123,11 +124,12 @@ class FilesDownloadWorker( val behaviour = inputData.keyValueMap[BEHAVIOUR] as String val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String val packageName = inputData.keyValueMap[PACKAGE_NAME] as String + downloadBinder = FileDownloaderBinder() showDownloadingFilesNotification() addAccountUpdateListener() - download(user, file, behaviour, downloadType, activityName, packageName) + requestDownloads(user, file, behaviour, downloadType, activityName, packageName) Result.success() } catch (t: Throwable) { @@ -135,7 +137,7 @@ class FilesDownloadWorker( } } - private fun download( + private fun requestDownloads( user: User, file: OCFile, behaviour: String, @@ -145,7 +147,7 @@ class FilesDownloadWorker( ) { val requestedDownloads: AbstractList = Vector() try { - val newDownload = DownloadFileOperation( + val operation = DownloadFileOperation( user, file, behaviour, @@ -154,17 +156,17 @@ class FilesDownloadWorker( context, downloadType ) - newDownload.addDatatransferProgressListener(this) - newDownload.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder?) + operation.addDatatransferProgressListener(this) + operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder?) val putResult: Pair = pendingDownloads.putIfAbsent( user.accountName, file.remotePath, - newDownload + operation ) val downloadKey = putResult.first requestedDownloads.add(downloadKey) - sendBroadcastNewDownload(newDownload, putResult.second) + sendBroadcastNewDownload(operation, putResult.second) } catch (e: IllegalArgumentException) { Log_OC.e(TAG, "Not enough information provided in intent: " + e.message) } @@ -183,47 +185,59 @@ class FilesDownloadWorker( private fun downloadFile(downloadKey: String) { startedDownload = true currentDownload = pendingDownloads.get(downloadKey) - if (currentDownload != null) { - if (accountManager.exists(currentDownload?.user?.toPlatformAccount())) { - notifyDownloadStart(currentDownload!!) - var downloadResult: RemoteOperationResult<*>? = null - try { - /// prepare client object to send the request to the ownCloud server - val currentDownloadAccount: Account? = currentDownload?.user?.toPlatformAccount() - val currentDownloadUser = accountManager.getUser(currentDownloadAccount?.name) - if (currentUser != currentDownloadUser) { - currentUser = currentDownloadUser - storageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) - } // else, reuse storage manager from previous operation - - val ocAccount = currentDownloadUser.get().toOwnCloudAccount() - downloadClient = - OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, context) - - downloadResult = currentDownload!!.execute(downloadClient) - if (downloadResult?.isSuccess == true && currentDownload?.downloadType === DownloadType.DOWNLOAD) { - saveDownloadedFile() - } - } catch (e: Exception) { - Log_OC.e(TAG, "Error downloading", e) - downloadResult = RemoteOperationResult(e) - } finally { - val removeResult: Pair = pendingDownloads.removePayload( - currentDownload?.user?.accountName, currentDownload?.remotePath - ) - if (downloadResult == null) { - downloadResult = RemoteOperationResult(RuntimeException("Error downloading…")) - } + if (currentDownload == null) { + return + } - currentDownload?.let { - notifyDownloadResult(it, downloadResult) - sendBroadcastDownloadFinished(it, downloadResult, removeResult.second) - } - } - } else { - cancelPendingDownloads(currentDownload?.user?.accountName) + val isAccountExist = accountManager.exists(currentDownload?.user?.toPlatformAccount()) + if (!isAccountExist) { + cancelPendingDownloads(currentDownload?.user?.accountName) + return + } + + notifyDownloadStart(currentDownload!!) + var downloadResult: RemoteOperationResult<*>? = null + try { + val ocAccount = getOCAccountForDownload() + downloadClient = + OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, context) + + downloadResult = currentDownload?.execute(downloadClient) + if (downloadResult?.isSuccess == true && currentDownload?.downloadType === DownloadType.DOWNLOAD) { + saveDownloadedFile() } + } catch (e: Exception) { + Log_OC.e(TAG, "Error downloading", e) + downloadResult = RemoteOperationResult(e) + } finally { + cleanupDownloadProcess(downloadResult) + } + } + + private fun getOCAccountForDownload(): OwnCloudAccount { + val currentDownloadAccount = currentDownload?.user?.toPlatformAccount() + val currentDownloadUser = accountManager.getUser(currentDownloadAccount?.name) + if (currentUser != currentDownloadUser) { + currentUser = currentDownloadUser + storageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) + } + return currentDownloadUser.get().toOwnCloudAccount() + } + + private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { + var downloadResult = result + val removeResult: Pair = pendingDownloads.removePayload( + currentDownload?.user?.accountName, currentDownload?.remotePath + ) + + if (downloadResult == null) { + downloadResult = RemoteOperationResult(RuntimeException("Error downloading…")) + } + + currentDownload?.let { + notifyDownloadResult(it, downloadResult) + sendBroadcastDownloadFinished(it, downloadResult, removeResult.second) } } From c419604ae5df6e05900b3d8227ece30f369275e1 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 12:26:37 +0100 Subject: [PATCH 007/189] Remove FileDownloader Service Signed-off-by: alperozturk --- .../android/files/FileMenuFilterIT.kt | 4 +- .../java/com/nextcloud/test/TestActivity.kt | 4 +- .../nextcloud/client/di/ComponentsModule.java | 4 - .../files/downloader/FilesDownloadHelper.kt | 4 +- .../files/downloader/FilesDownloadWorker.kt | 33 +- .../client/jobs/BackgroundJobManager.kt | 4 +- .../client/jobs/BackgroundJobManagerImpl.kt | 5 +- .../nextcloud/client/jobs/FilesExportWork.kt | 20 +- .../android/files/FileMenuFilter.java | 6 +- .../files/services/FileDownloader.java | 686 ------------------ .../operations/SynchronizeFileOperation.java | 17 +- .../SynchronizeFolderOperation.java | 21 +- .../providers/DocumentsStorageProvider.java | 3 +- .../android/services/SyncFolderHandler.java | 16 +- .../android/ui/activity/ComponentsGetter.java | 4 +- .../ui/activity/ConflictsResolveActivity.kt | 19 +- .../android/ui/activity/FileActivity.java | 16 +- .../ui/activity/FileDisplayActivity.java | 41 +- .../ui/activity/ManageAccountsActivity.java | 12 +- .../ui/fragment/FileDetailFragment.java | 8 +- .../android/ui/fragment/FileFragment.java | 5 +- .../ui/helpers/FileOperationsHelper.java | 4 +- .../ui/preview/PreviewImageActivity.java | 28 +- .../ui/preview/PreviewMediaFragment.java | 7 +- 24 files changed, 146 insertions(+), 825 deletions(-) delete mode 100644 app/src/main/java/com/owncloud/android/files/services/FileDownloader.java diff --git a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt index 4e92898407b3..e031d92ccafe 100644 --- a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt @@ -23,6 +23,7 @@ package com.owncloud.android.files import androidx.test.core.app.launchActivity import androidx.test.ext.junit.runners.AndroidJUnit4 import com.nextcloud.client.account.User +import com.nextcloud.client.files.downloader.FilesDownloadWorker import com.nextcloud.test.TestActivity import com.nextcloud.utils.EditorUtils import com.owncloud.android.AbstractIT @@ -30,7 +31,6 @@ import com.owncloud.android.R import com.owncloud.android.datamodel.ArbitraryDataProvider import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.files.services.FileDownloader import com.owncloud.android.files.services.FileUploader import com.owncloud.android.lib.resources.files.model.FileLockType import com.owncloud.android.lib.resources.status.CapabilityBooleanType @@ -62,7 +62,7 @@ class FileMenuFilterIT : AbstractIT() { private lateinit var mockFileUploaderBinder: FileUploader.FileUploaderBinder @MockK - private lateinit var mockFileDownloaderBinder: FileDownloader.FileDownloaderBinder + private lateinit var mockFileDownloaderBinder: FilesDownloadWorker.FileDownloaderBinder @MockK private lateinit var mockOperationsServiceBinder: OperationsService.OperationsServiceBinder diff --git a/app/src/debug/java/com/nextcloud/test/TestActivity.kt b/app/src/debug/java/com/nextcloud/test/TestActivity.kt index 7844f1379e9a..90c4ecc19a82 100644 --- a/app/src/debug/java/com/nextcloud/test/TestActivity.kt +++ b/app/src/debug/java/com/nextcloud/test/TestActivity.kt @@ -25,6 +25,7 @@ import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment import androidx.swiperefreshlayout.widget.SwipeRefreshLayout +import com.nextcloud.client.files.downloader.FilesDownloadWorker import com.nextcloud.client.network.Connectivity import com.nextcloud.client.network.ConnectivityService import com.nextcloud.utils.EditorUtils @@ -33,7 +34,6 @@ import com.owncloud.android.databinding.TestLayoutBinding import com.owncloud.android.datamodel.ArbitraryDataProviderImpl import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.files.services.FileDownloader import com.owncloud.android.files.services.FileUploader import com.owncloud.android.lib.resources.status.OCCapability import com.owncloud.android.lib.resources.status.OwnCloudVersion @@ -130,7 +130,7 @@ class TestActivity : return null } - override fun getFileDownloaderBinder(): FileDownloader.FileDownloaderBinder? { + override fun getFileDownloaderBinder(): FilesDownloadWorker.FileDownloaderBinder? { return null } diff --git a/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java b/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java index 08f5b986e330..0380bd974cf7 100644 --- a/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java +++ b/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java @@ -46,7 +46,6 @@ import com.owncloud.android.authentication.AuthenticatorActivity; import com.owncloud.android.authentication.DeepLinkLoginActivity; import com.owncloud.android.files.BootupBroadcastReceiver; -import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.providers.DiskLruImageCacheFileProvider; import com.owncloud.android.providers.DocumentsStorageProvider; @@ -326,9 +325,6 @@ abstract class ComponentsModule { @ContributesAndroidInjector abstract FileUploader fileUploader(); - @ContributesAndroidInjector - abstract FileDownloader fileDownloader(); - @ContributesAndroidInjector abstract BootupBroadcastReceiver bootupBroadcastReceiver(); diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt index b5e316a28871..71f833c07bdc 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt @@ -45,10 +45,10 @@ class FilesDownloadHelper { user: User, ocFile: OCFile, behaviour: String, - downloadType: DownloadType, + downloadType: DownloadType?, activityName: String, packageName: String, - conflictUploadId: Long + conflictUploadId: Long? ) { backgroundJobManager.startFilesDownloadJob( user, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index 03e114612504..dfdf51781a96 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -99,6 +99,14 @@ class FilesDownloadWorker( const val EXTRA_REMOTE_PATH = "REMOTE_PATH" const val EXTRA_LINKED_TO_PATH = "LINKED_TO" const val ACCOUNT_NAME = "ACCOUNT_NAME" + + fun getDownloadAddedMessage(): String { + return FilesDownloadWorker::class.java.name + "DOWNLOAD_ADDED" + } + + fun getDownloadFinishMessage(): String { + return FilesDownloadWorker::class.java.name + "DOWNLOAD_FINISH" + } } private var notification: Notification? = null @@ -436,14 +444,6 @@ class FilesDownloadWorker( pendingDownloads.remove(accountName) } - private fun getDownloadAddedMessage(): String { - return FilesDownloadWorker::class.java.name + "DOWNLOAD_ADDED" - } - - private fun getDownloadFinishMessage(): String { - return FilesDownloadWorker::class.java.name + "DOWNLOAD_FINISH" - } - private fun sendBroadcastNewDownload( download: DownloadFileOperation, linkedToRemotePath: String @@ -533,6 +533,23 @@ class FilesDownloadWorker( return user != null && file != null && pendingDownloads.contains(user.accountName, file.remotePath) } + fun addDatatransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { + if (file == null || listener == null) { + return + } + mBoundListeners[file.fileId] = listener + } + + fun removeDatatransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { + if (file == null || listener == null) { + return + } + val fileId = file.fileId + if (mBoundListeners[fileId] === listener) { + mBoundListeners.remove(fileId) + } + } + override fun onTransferProgress( progressRate: Long, totalTransferredSoFar: Long, totalToTransfer: Long, fileName: String diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index fbcc04922e17..30f7ab3c7595 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -149,10 +149,10 @@ interface BackgroundJobManager { user: User, ocFile: OCFile, behaviour: String, - downloadType: DownloadType, + downloadType: DownloadType?, activityName: String, packageName: String, - conflictUploadId: Long + conflictUploadId: Long? ) fun startPdfGenerateAndUploadWork(user: User, uploadFolder: String, imagePaths: List, pdfPath: String) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index d291189269de..943e9c6d0fc3 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -42,7 +42,6 @@ import com.nextcloud.client.files.downloader.FilesDownloadWorker import com.nextcloud.client.preferences.AppPreferences import com.owncloud.android.datamodel.OCFile import com.owncloud.android.operations.DownloadType -import java.io.File import java.util.Date import java.util.UUID import java.util.concurrent.TimeUnit @@ -513,10 +512,10 @@ internal class BackgroundJobManagerImpl( user: User, ocFile: OCFile, behaviour: String, - downloadType: DownloadType, + downloadType: DownloadType?, activityName: String, packageName: String, - conflictUploadId: Long + conflictUploadId: Long? ) { val data = workDataOf( FilesDownloadWorker.USER to user, diff --git a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt index cb8172655ccf..60d9eb16beb0 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt @@ -33,13 +33,12 @@ import androidx.core.app.NotificationCompat import androidx.work.Worker import androidx.work.WorkerParameters import com.nextcloud.client.account.User +import com.nextcloud.client.files.downloader.FilesDownloadHelper import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.files.services.FileDownloader import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.operations.DownloadType -import com.owncloud.android.ui.dialog.SendShareDialog import com.owncloud.android.ui.notifications.NotificationUtils import com.owncloud.android.utils.FileExportUtils import com.owncloud.android.utils.FileStorageUtils @@ -112,14 +111,15 @@ class FilesExportWork( } private fun downloadFile(ocFile: OCFile) { - val i = Intent(appContext, FileDownloader::class.java) - i.putExtra(FileDownloader.EXTRA_USER, user) - i.putExtra(FileDownloader.EXTRA_FILE, ocFile) - i.putExtra(SendShareDialog.PACKAGE_NAME, "") - i.putExtra(SendShareDialog.ACTIVITY_NAME, "") - i.putExtra(FileDownloader.DOWNLOAD_TYPE, DownloadType.EXPORT) - - FileDownloader(i) + FilesDownloadHelper().downloadFile( + user, + ocFile, + behaviour = "", + packageName = "", + activityName = "", + conflictUploadId = 0L, + downloadType = DownloadType.EXPORT + ) } private fun showErrorNotification(successfulExports: Int) { diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index ecf266cc045c..e1d9ead64139 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -31,11 +31,11 @@ import com.nextcloud.android.files.FileLockingHelper; import com.nextcloud.client.account.User; import com.nextcloud.client.editimage.EditImageActivity; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.utils.EditorUtils; import com.owncloud.android.R; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.lib.resources.status.OCCapability; import com.owncloud.android.services.OperationsService.OperationsServiceBinder; @@ -380,7 +380,7 @@ private boolean anyFileSynchronizing() { if (componentsGetter != null && !files.isEmpty() && user != null) { OperationsServiceBinder opsBinder = componentsGetter.getOperationsServiceBinder(); FileUploaderBinder uploaderBinder = componentsGetter.getFileUploaderBinder(); - FileDownloaderBinder downloaderBinder = componentsGetter.getFileDownloaderBinder(); + FilesDownloadWorker.FileDownloaderBinder downloaderBinder = componentsGetter.getFileDownloaderBinder(); synchronizing = anyFileSynchronizing(opsBinder) || // comparing local and remote anyFileDownloading(downloaderBinder) || anyFileUploading(uploaderBinder); @@ -398,7 +398,7 @@ private boolean anyFileSynchronizing(OperationsServiceBinder opsBinder) { return synchronizing; } - private boolean anyFileDownloading(FileDownloaderBinder downloaderBinder) { + private boolean anyFileDownloading(FilesDownloadWorker.FileDownloaderBinder downloaderBinder) { boolean downloading = false; if (downloaderBinder != null) { for (Iterator iterator = files.iterator(); !downloading && iterator.hasNext(); ) { diff --git a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java deleted file mode 100644 index b537db5fbf9d..000000000000 --- a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java +++ /dev/null @@ -1,686 +0,0 @@ -/* - * ownCloud Android client application - * - * Copyright (C) 2012 Bartek Przybylski - * Copyright (C) 2012-2016 ownCloud Inc. - * - * 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.files.services; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.OnAccountsUpdateListener; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.graphics.BitmapFactory; -import android.os.Binder; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.Process; -import android.util.Pair; - -import com.nextcloud.client.account.User; -import com.nextcloud.client.account.UserAccountManager; -import com.nextcloud.client.files.downloader.DownloadTask; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; -import com.nextcloud.java.util.Optional; -import com.nextcloud.utils.extensions.IntentExtensionsKt; -import com.owncloud.android.MainApp; -import com.owncloud.android.R; -import com.owncloud.android.authentication.AuthenticatorActivity; -import com.owncloud.android.datamodel.FileDataStorageManager; -import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.datamodel.UploadsStorageManager; -import com.owncloud.android.lib.common.OwnCloudAccount; -import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; -import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; -import com.owncloud.android.lib.common.operations.RemoteOperationResult; -import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; -import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.lib.resources.files.FileUtils; -import com.owncloud.android.operations.DownloadFileOperation; -import com.owncloud.android.operations.DownloadType; -import com.owncloud.android.providers.DocumentsStorageProvider; -import com.owncloud.android.ui.activity.ConflictsResolveActivity; -import com.owncloud.android.ui.activity.FileActivity; -import com.owncloud.android.ui.activity.FileDisplayActivity; -import com.owncloud.android.ui.dialog.SendShareDialog; -import com.owncloud.android.ui.fragment.OCFileListFragment; -import com.owncloud.android.ui.notifications.NotificationUtils; -import com.owncloud.android.ui.preview.PreviewImageActivity; -import com.owncloud.android.ui.preview.PreviewImageFragment; -import com.owncloud.android.utils.ErrorMessageAdapter; -import com.owncloud.android.utils.MimeTypeUtil; -import com.owncloud.android.utils.theme.ViewThemeUtils; - -import java.io.File; -import java.security.SecureRandom; -import java.util.AbstractList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Vector; - -import javax.inject.Inject; - -import androidx.core.app.NotificationCompat; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import androidx.work.OneTimeWorkRequest; -import androidx.work.WorkManager; -import androidx.work.WorkRequest; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import static android.content.Context.NOTIFICATION_SERVICE; - -public class FileDownloader implements OnDatatransferProgressListener, OnAccountsUpdateListener { - - private final Context context = MainApp.getAppContext(); - private final Intent intent; - - private static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED"; - private static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH"; - - public static final String EXTRA_USER = "USER"; - public static final String EXTRA_FILE = "FILE"; - public static final String EXTRA_DOWNLOAD_RESULT = "RESULT"; - public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; - public static final String EXTRA_LINKED_TO_PATH = "LINKED_TO"; - public static final String ACCOUNT_NAME = "ACCOUNT_NAME"; - public static final String DOWNLOAD_TYPE = "DOWNLOAD_TYPE"; - - private static final int FOREGROUND_SERVICE_ID = 412; - - private static final String TAG = FileDownloader.class.getSimpleName(); - - private Looper mServiceLooper; - private ServiceHandler mServiceHandler; - private IBinder mBinder; - private OwnCloudClient mDownloadClient; - private Optional currentUser = Optional.empty(); - private FileDataStorageManager mStorageManager; - - private IndexedForest mPendingDownloads = new IndexedForest<>(); - - private DownloadFileOperation mCurrentDownload; - - private NotificationManager mNotificationManager; - private NotificationCompat.Builder mNotificationBuilder; - private int mLastPercent; - - private Notification mNotification; - - private long conflictUploadId; - - public boolean mStartedDownload = false; - - @Inject UserAccountManager accountManager; - @Inject UploadsStorageManager uploadsStorageManager; - @Inject LocalBroadcastManager localBroadcastManager; - @Inject ViewThemeUtils viewThemeUtils; - - public static String getDownloadAddedMessage() { - return FileDownloader.class.getName() + DOWNLOAD_ADDED_MESSAGE; - } - - public static String getDownloadFinishMessage() { - return FileDownloader.class.getName() + DOWNLOAD_FINISH_MESSAGE; - } - - public FileDownloader(Intent intent) { - this.intent = intent; - Log_OC.d(TAG, "Creating service"); - mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); - HandlerThread thread = new HandlerThread("FileDownloaderThread", Process.THREAD_PRIORITY_BACKGROUND); - thread.start(); - mServiceLooper = thread.getLooper(); - mServiceHandler = new ServiceHandler(mServiceLooper, this); - mBinder = new FileDownloaderBinder(); - - NotificationCompat.Builder builder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).setContentTitle( - context.getResources().getString(R.string.app_name)) - .setContentText(context.getResources().getString(R.string.foreground_service_download)) - .setSmallIcon(R.drawable.notification_icon) - .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.notification_icon)); - - - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - builder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD); - } - - mNotification = builder.build(); - - // add AccountsUpdatedListener - AccountManager am = AccountManager.get(context); - am.addOnAccountsUpdatedListener(this, null, false); - } - - @Override - protected void finalize() throws Throwable { - Log_OC.v(TAG, "Destroying service"); - mBinder = null; - mServiceHandler = null; - mServiceLooper.quit(); - mServiceLooper = null; - mNotificationManager = null; - - // remove AccountsUpdatedListener - AccountManager am = AccountManager.get(context); - am.removeOnAccountsUpdatedListener(this); - super.finalize(); - } - - public void download() { - final User user = IntentExtensionsKt.getParcelableArgument(intent, EXTRA_USER, User.class); - final OCFile file = IntentExtensionsKt.getParcelableArgument(intent, EXTRA_FILE, OCFile.class); - final String behaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); - - DownloadType downloadType = DownloadType.DOWNLOAD; - if (intent.hasExtra(DOWNLOAD_TYPE)) { - downloadType = IntentExtensionsKt.getSerializableArgument(intent, DOWNLOAD_TYPE, DownloadType.class); - } - String activityName = intent.getStringExtra(SendShareDialog.ACTIVITY_NAME); - String packageName = intent.getStringExtra(SendShareDialog.PACKAGE_NAME); - conflictUploadId = intent.getLongExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, -1); - AbstractList requestedDownloads = new Vector(); - try { - DownloadFileOperation newDownload = new DownloadFileOperation(user, - file, - behaviour, - activityName, - packageName, - context, - downloadType); - newDownload.addDatatransferProgressListener(this); - newDownload.addDatatransferProgressListener((FileDownloaderBinder) mBinder); - Pair putResult = mPendingDownloads.putIfAbsent(user.getAccountName(), - file.getRemotePath(), - newDownload); - if (putResult != null) { - String downloadKey = putResult.first; - requestedDownloads.add(downloadKey); - sendBroadcastNewDownload(newDownload, putResult.second); - } // else, file already in the queue of downloads; don't repeat the request - - } catch (IllegalArgumentException e) { - Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage()); - } - - if (requestedDownloads.size() > 0) { - Message msg = mServiceHandler.obtainMessage(); - // msg.arg1 = startId; - msg.obj = requestedDownloads; - mServiceHandler.sendMessage(msg); - } - } - - @Override - public void onAccountsUpdated(Account[] accounts) { - //review the current download and cancel it if its account doesn't exist - if (mCurrentDownload != null && !accountManager.exists(mCurrentDownload.getUser().toPlatformAccount())) { - mCurrentDownload.cancel(); - } - // The rest of downloads are cancelled when they try to start - } - - /** - * Binder to let client components to perform operations on the queue of downloads. - *

- * It provides by itself the available operations. - */ - public class FileDownloaderBinder2 extends Binder implements OnDatatransferProgressListener { - - /** - * Map of listeners that will be reported about progress of downloads from a - * {@link FileDownloaderBinder} - * instance. - */ - private Map mBoundListeners = - new HashMap(); - - - /** - * Cancels a pending or current download of a remote file. - * - * @param account ownCloud account where the remote file is stored. - * @param file A file in the queue of pending downloads - */ - public void cancel(Account account, OCFile file) { - Pair removeResult = - mPendingDownloads.remove(account.name, file.getRemotePath()); - DownloadFileOperation download = removeResult.first; - if (download != null) { - download.cancel(); - } else { - if (mCurrentDownload != null && currentUser.isPresent() && - mCurrentDownload.getRemotePath().startsWith(file.getRemotePath()) && - account.name.equals(currentUser.get().getAccountName())) { - mCurrentDownload.cancel(); - } - } - } - - /** - * Cancels all the downloads for an account - */ - public void cancel(String accountName) { - if (mCurrentDownload != null && mCurrentDownload.getUser().nameEquals(accountName)) { - mCurrentDownload.cancel(); - } - // Cancel pending downloads - cancelPendingDownloads(accountName); - } - - /** - * Returns True when the file described by 'file' in the ownCloud account 'account' - * is downloading or waiting to download. - * - * If 'file' is a directory, returns 'true' if any of its descendant files is downloading or - * waiting to download. - * - * @param user user where the remote file is stored. - * @param file A file that could be in the queue of downloads. - */ - public boolean isDownloading(User user, OCFile file) { - return user != null && file != null && mPendingDownloads.contains(user.getAccountName(), file.getRemotePath()); - } - - - /** - * Adds a listener interested in the progress of the download for a concrete file. - * - * @param listener Object to notify about progress of transfer. - * @param file {@link OCFile} of interest for listener. - */ - public void addDatatransferProgressListener(OnDatatransferProgressListener listener, OCFile file) { - if (file == null || listener == null) { - return; - } - mBoundListeners.put(file.getFileId(), listener); - } - - - /** - * Removes a listener interested in the progress of the download for a concrete file. - * - * @param listener Object to notify about progress of transfer. - * @param file {@link OCFile} of interest for listener. - */ - public void removeDatatransferProgressListener(OnDatatransferProgressListener listener, OCFile file) { - if (file == null || listener == null) { - return; - } - Long fileId = file.getFileId(); - if (mBoundListeners.get(fileId) == listener) { - mBoundListeners.remove(fileId); - } - } - - @Override - public void onTransferProgress(long progressRate, long totalTransferredSoFar, - long totalToTransfer, String fileName) { - OnDatatransferProgressListener boundListener = - mBoundListeners.get(mCurrentDownload.getFile().getFileId()); - if (boundListener != null) { - boundListener.onTransferProgress(progressRate, totalTransferredSoFar, - totalToTransfer, fileName); - } - } - - } - - /** - * Download worker. Performs the pending downloads in the order they were requested. - - * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}. - */ - private static class ServiceHandler extends Handler { - // don't make it a final class, and don't remove the static ; lint will warn about a - // possible memory leak - FileDownloader mService; - - public ServiceHandler(Looper looper, FileDownloader service) { - super(looper); - if (service == null) { - throw new IllegalArgumentException("Received invalid NULL in parameter 'service'"); - } - mService = service; - } - - @Override - public void handleMessage(Message msg) { - @SuppressWarnings("unchecked") - AbstractList requestedDownloads = (AbstractList) msg.obj; - if (msg.obj != null) { - Iterator it = requestedDownloads.iterator(); - while (it.hasNext()) { - String next = it.next(); - mService.downloadFile(next); - } - } - mService.mStartedDownload=false; - - (new Handler()).postDelayed(() -> { - if(!mService.mStartedDownload){ - mService.mNotificationManager.cancel(R.string.downloader_download_in_progress_ticker); - } - Log_OC.d(TAG, "Stopping after command with id " + msg.arg1); - mService.mNotificationManager.cancel(FOREGROUND_SERVICE_ID); - }, 2000); - } - } - - - void downloadFile(String downloadKey) { - - mStartedDownload = true; - mCurrentDownload = mPendingDownloads.get(downloadKey); - - if (mCurrentDownload != null) { - // Detect if the account exists - if (accountManager.exists(mCurrentDownload.getUser().toPlatformAccount())) { - notifyDownloadStart(mCurrentDownload); - RemoteOperationResult downloadResult = null; - try { - /// prepare client object to send the request to the ownCloud server - Account currentDownloadAccount = mCurrentDownload.getUser().toPlatformAccount(); - Optional currentDownloadUser = accountManager.getUser(currentDownloadAccount.name); - if (!currentUser.equals(currentDownloadUser)) { - currentUser = currentDownloadUser; - mStorageManager = new FileDataStorageManager(currentUser.get(), context.getContentResolver()); - } // else, reuse storage manager from previous operation - - // always get client from client manager, to get fresh credentials in case - // of update - OwnCloudAccount ocAccount = currentDownloadUser.get().toOwnCloudAccount(); - mDownloadClient = OwnCloudClientManagerFactory.getDefaultSingleton(). - getClientFor(ocAccount, context); - - - /// perform the download - downloadResult = mCurrentDownload.execute(mDownloadClient); - if (downloadResult.isSuccess() && mCurrentDownload.getDownloadType() == DownloadType.DOWNLOAD) { - saveDownloadedFile(); - } - - } catch (Exception e) { - Log_OC.e(TAG, "Error downloading", e); - downloadResult = new RemoteOperationResult(e); - - } finally { - Pair removeResult = mPendingDownloads.removePayload( - mCurrentDownload.getUser().getAccountName(), mCurrentDownload.getRemotePath()); - - if (downloadResult == null) { - downloadResult = new RemoteOperationResult(new RuntimeException("Error downloading…")); - } - - /// notify result - notifyDownloadResult(mCurrentDownload, downloadResult); - sendBroadcastDownloadFinished(mCurrentDownload, downloadResult, removeResult.second); - } - } else { - cancelPendingDownloads(mCurrentDownload.getUser().getAccountName()); - } - } - } - - - /** - * Updates the OC File after a successful download. - * - * TODO move to DownloadFileOperation - * unify with code from {@link DocumentsStorageProvider} and {@link DownloadTask}. - */ - private void saveDownloadedFile() { - OCFile file = mStorageManager.getFileById(mCurrentDownload.getFile().getFileId()); - - if (file == null) { - // try to get file via path, needed for overwriting existing files on conflict dialog - file = mStorageManager.getFileByDecryptedRemotePath(mCurrentDownload.getFile().getRemotePath()); - } - - if (file == null) { - Log_OC.e(this, "Could not save " + mCurrentDownload.getFile().getRemotePath()); - return; - } - - long syncDate = System.currentTimeMillis(); - file.setLastSyncDateForProperties(syncDate); - file.setLastSyncDateForData(syncDate); - file.setUpdateThumbnailNeeded(true); - file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp()); - file.setModificationTimestampAtLastSyncForData(mCurrentDownload.getModificationTimestamp()); - file.setEtag(mCurrentDownload.getEtag()); - file.setMimeType(mCurrentDownload.getMimeType()); - file.setStoragePath(mCurrentDownload.getSavePath()); - file.setFileLength(new File(mCurrentDownload.getSavePath()).length()); - file.setRemoteId(mCurrentDownload.getFile().getRemoteId()); - mStorageManager.saveFile(file); - if (MimeTypeUtil.isMedia(mCurrentDownload.getMimeType())) { - FileDataStorageManager.triggerMediaScan(file.getStoragePath(), file); - } - mStorageManager.saveConflict(file, null); - } - - /** - * Creates a status notification to show the download progress - * - * @param download Download operation starting. - */ - private void notifyDownloadStart(DownloadFileOperation download) { - /// create status notification with a progress bar - mLastPercent = 0; - mNotificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils); - mNotificationBuilder - .setSmallIcon(R.drawable.notification_icon) - .setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) - .setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) - .setOngoing(true) - .setProgress(100, 0, download.getSize() < 0) - .setContentText( - String.format(context.getString(R.string.downloader_download_in_progress_content), 0, - new File(download.getSavePath()).getName())); - - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - mNotificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD); - } - - /// includes a pending intent in the notification showing the details view of the file - Intent showDetailsIntent = null; - if (PreviewImageFragment.canBePreviewed(download.getFile())) { - showDetailsIntent = new Intent(context, PreviewImageActivity.class); - } else { - showDetailsIntent = new Intent(context, FileDisplayActivity.class); - } - showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, download.getFile()); - showDetailsIntent.putExtra(FileActivity.EXTRA_USER, download.getUser()); - showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - - mNotificationBuilder.setContentIntent(PendingIntent.getActivity(context, (int) System.currentTimeMillis(), - showDetailsIntent, PendingIntent.FLAG_IMMUTABLE)); - - - if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); - } - if (mNotificationManager != null) { - mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotificationBuilder.build()); - } - } - - - /** - * Callback method to update the progress bar in the status notification. - */ - @Override - public void onTransferProgress(long progressRate, long totalTransferredSoFar, - long totalToTransfer, String filePath) { - int percent = (int) (100.0 * ((double) totalTransferredSoFar) / ((double) totalToTransfer)); - if (percent != mLastPercent) { - mNotificationBuilder.setProgress(100, percent, totalToTransfer < 0); - String fileName = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1); - String text = String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName); - mNotificationBuilder.setContentText(text); - - if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); - } - - if (mNotificationManager != null) { - mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, - mNotificationBuilder.build()); - } - } - mLastPercent = percent; - } - - - /** - * Updates the status notification with the result of a download operation. - * - * @param downloadResult Result of the download operation. - * @param download Finished download operation - */ - @SuppressFBWarnings("DMI") - private void notifyDownloadResult(DownloadFileOperation download, - RemoteOperationResult downloadResult) { - if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); - } - - if (!downloadResult.isCancelled()) { - if (downloadResult.isSuccess()) { - if (conflictUploadId > 0) { - uploadsStorageManager.removeUpload(conflictUploadId); - } - // Dont show notification except an error has occured. - return; - } - int tickerId = downloadResult.isSuccess() ? - R.string.downloader_download_succeeded_ticker : R.string.downloader_download_failed_ticker; - - boolean needsToUpdateCredentials = ResultCode.UNAUTHORIZED == downloadResult.getCode(); - tickerId = needsToUpdateCredentials ? - R.string.downloader_download_failed_credentials_error : tickerId; - - mNotificationBuilder - .setTicker(context.getString(tickerId)) - .setContentTitle(context.getString(tickerId)) - .setAutoCancel(true) - .setOngoing(false) - .setProgress(0, 0, false); - - if (needsToUpdateCredentials) { - configureUpdateCredentialsNotification(download.getUser()); - - } else { - // TODO put something smart in showDetailsIntent - Intent showDetailsIntent = new Intent(); - mNotificationBuilder.setContentIntent(PendingIntent.getActivity(context, (int) System.currentTimeMillis(), - showDetailsIntent, PendingIntent.FLAG_IMMUTABLE)); - } - - mNotificationBuilder.setContentText(ErrorMessageAdapter.getErrorCauseMessage(downloadResult, - download, context.getResources())); - - if (mNotificationManager != null) { - mNotificationManager.notify((new SecureRandom()).nextInt(), mNotificationBuilder.build()); - - // Remove success notification - if (downloadResult.isSuccess()) { - // Sleep 2 seconds, so show the notification before remove it - NotificationUtils.cancelWithDelay(mNotificationManager, - R.string.downloader_download_succeeded_ticker, 2000); - } - } - } - } - - private void configureUpdateCredentialsNotification(User user) { - // let the user update credentials with one click - Intent updateAccountCredentials = new Intent(context, AuthenticatorActivity.class); - updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()); - updateAccountCredentials.putExtra( - AuthenticatorActivity.EXTRA_ACTION, - AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN - ); - updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND); - mNotificationBuilder.setContentIntent( - PendingIntent.getActivity(context, - (int) System.currentTimeMillis(), - updateAccountCredentials, - PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE) - ); - } - - - /** - * Sends a broadcast when a download finishes in order to the interested activities can - * update their view - * - * @param download Finished download operation - * @param downloadResult Result of the download operation - * @param unlinkedFromRemotePath Path in the downloads tree where the download was unlinked from - */ - private void sendBroadcastDownloadFinished( - DownloadFileOperation download, - RemoteOperationResult downloadResult, - String unlinkedFromRemotePath) { - - Intent end = new Intent(getDownloadFinishMessage()); - end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess()); - end.putExtra(ACCOUNT_NAME, download.getUser().getAccountName()); - end.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath()); - end.putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.getBehaviour()); - end.putExtra(SendShareDialog.ACTIVITY_NAME, download.getActivityName()); - end.putExtra(SendShareDialog.PACKAGE_NAME, download.getPackageName()); - if (unlinkedFromRemotePath != null) { - end.putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath); - } - end.setPackage(context.getPackageName()); - localBroadcastManager.sendBroadcast(end); - } - - - /** - * Sends a broadcast when a new download is added to the queue. - * - * @param download Added download operation - * @param linkedToRemotePath Path in the downloads tree where the download was linked to - */ - private void sendBroadcastNewDownload(DownloadFileOperation download, - String linkedToRemotePath) { - Intent added = new Intent(getDownloadAddedMessage()); - added.putExtra(ACCOUNT_NAME, download.getUser().getAccountName()); - added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath()); - added.putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath); - added.setPackage(context.getPackageName()); - localBroadcastManager.sendBroadcast(added); - } - - private void cancelPendingDownloads(String accountName) { - mPendingDownloads.remove(accountName); - } -} diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java index 80c4e2411a36..4efa2c0b7841 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -22,13 +22,12 @@ package com.owncloud.android.operations; import android.content.Context; -import android.content.Intent; import android.text.TextUtils; import com.nextcloud.client.account.User; +import com.nextcloud.client.files.downloader.FilesDownloadHelper; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.NameCollisionPolicy; import com.owncloud.android.lib.common.OwnCloudClient; @@ -317,11 +316,17 @@ private void requestForUpload(OCFile file) { * @param file OCFile object representing the file to download */ private void requestForDownload(OCFile file) { - Intent i = new Intent(mContext, FileDownloader.class); - i.putExtra(FileDownloader.EXTRA_USER, mUser); - i.putExtra(FileDownloader.EXTRA_FILE, file); + FilesDownloadHelper downloadHelper = new FilesDownloadHelper(); + + downloadHelper.downloadFile( + mUser, + file, + "", + null, + "", + "", + null); - new FileDownloader(i); mTransferWasRequested = true; } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index e3aeb18eaab1..5bfd7ad0dc0d 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -25,10 +25,10 @@ import android.text.TextUtils; import com.nextcloud.client.account.User; +import com.nextcloud.client.files.downloader.FilesDownloadHelper; import com.owncloud.android.datamodel.DecryptedFolderMetadata; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.OperationCancelledException; import com.owncloud.android.lib.common.operations.RemoteOperationResult; @@ -451,14 +451,17 @@ private void startDirectDownloads() throws OperationCancelledException { if (mCancellationRequested.get()) { throw new OperationCancelledException(); } - Intent i = new Intent(mContext, FileDownloader.class); - i.putExtra(FileDownloader.EXTRA_USER, user); - i.putExtra(FileDownloader.EXTRA_FILE, file); - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - mContext.startForegroundService(i); - } else { - mContext.startService(i); - } + + FilesDownloadHelper downloadHelper = new FilesDownloadHelper(); + + downloadHelper.downloadFile( + user, + file, + "", + null, + "", + "", + null); } } } diff --git a/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java b/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java index 9f76aa700637..a7f10ffac956 100644 --- a/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java +++ b/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java @@ -52,7 +52,6 @@ import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.ThumbnailsCacheManager; -import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.NameCollisionPolicy; import com.owncloud.android.lib.common.OwnCloudAccount; @@ -308,7 +307,7 @@ private boolean hasServerChange(Document document) throws FileNotFoundException /** * Updates the OC File after a successful download. * - * TODO unify with code from {@link FileDownloader} and {@link DownloadTask}. + * TODO unify with code from {@link com.nextcloud.client.files.downloader.FilesDownloadWorker} and {@link DownloadTask}. */ private void saveDownloadedFile(FileDataStorageManager storageManager, DownloadFileOperation dfo, OCFile file) { long syncDate = System.currentTimeMillis(); diff --git a/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java b/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java index 1f3c8dce5976..18329af5dc5d 100644 --- a/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java +++ b/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java @@ -28,8 +28,8 @@ import android.util.Pair; import com.nextcloud.client.account.User; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.files.services.IndexedForest; import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.OwnCloudClient; @@ -169,9 +169,9 @@ public void cancel(Account account, OCFile file){ * this is a fast and ugly patch. */ private void sendBroadcastNewSyncFolder(Account account, String remotePath) { - Intent added = new Intent(FileDownloader.getDownloadAddedMessage()); - added.putExtra(FileDownloader.ACCOUNT_NAME, account.name); - added.putExtra(FileDownloader.EXTRA_REMOTE_PATH, remotePath); + Intent added = new Intent(FilesDownloadWorker.Companion.getDownloadAddedMessage()); + added.putExtra(FilesDownloadWorker.ACCOUNT_NAME, account.name); + added.putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, remotePath); added.setPackage(mService.getPackageName()); LocalBroadcastManager.getInstance(mService.getApplicationContext()).sendBroadcast(added); } @@ -182,10 +182,10 @@ private void sendBroadcastNewSyncFolder(Account account, String remotePath) { */ private void sendBroadcastFinishedSyncFolder(Account account, String remotePath, boolean success) { - Intent finished = new Intent(FileDownloader.getDownloadFinishMessage()); - finished.putExtra(FileDownloader.ACCOUNT_NAME, account.name); - finished.putExtra(FileDownloader.EXTRA_REMOTE_PATH, remotePath); - finished.putExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, success); + Intent finished = new Intent(FilesDownloadWorker.Companion.getDownloadFinishMessage()); + finished.putExtra(FilesDownloadWorker.ACCOUNT_NAME, account.name); + finished.putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, remotePath); + finished.putExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, success); finished.setPackage(mService.getPackageName()); LocalBroadcastManager.getInstance(mService.getApplicationContext()).sendBroadcast(finished); } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java index 8c5d35eb5233..4b0ab8c6de2e 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java @@ -20,8 +20,8 @@ package com.owncloud.android.ui.activity; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.owncloud.android.datamodel.FileDataStorageManager; -import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.services.OperationsService.OperationsServiceBinder; import com.owncloud.android.ui.helpers.FileOperationsHelper; @@ -32,7 +32,7 @@ public interface ComponentsGetter { * To be invoked when the parent activity is fully created to get a reference * to the FileDownloader service API. */ - public FileDownloaderBinder getFileDownloaderBinder(); + public FilesDownloadWorker.FileDownloaderBinder getFileDownloaderBinder(); /** diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt index 830fee88af4f..4ac180376a21 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt @@ -21,13 +21,13 @@ import android.content.Intent import android.os.Bundle import android.widget.Toast import com.nextcloud.client.account.User +import com.nextcloud.client.files.downloader.FilesDownloadHelper import com.nextcloud.model.HTTPStatusCodes import com.nextcloud.utils.extensions.getParcelableArgument import com.owncloud.android.R import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.db.OCUpload -import com.owncloud.android.files.services.FileDownloader import com.owncloud.android.files.services.FileUploader import com.owncloud.android.files.services.NameCollisionPolicy import com.owncloud.android.lib.common.utils.Log_OC @@ -114,12 +114,17 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener Decision.KEEP_SERVER -> if (!shouldDeleteLocal()) { // Overwrite local file - val intent = Intent(baseContext, FileDownloader::class.java) - intent.putExtra(FileDownloader.EXTRA_USER, getUser().orElseThrow { RuntimeException() }) - intent.putExtra(FileDownloader.EXTRA_FILE, file) - intent.putExtra(EXTRA_CONFLICT_UPLOAD_ID, conflictUploadId) - - FileDownloader(intent) + file?.let { + FilesDownloadHelper().downloadFile( + user = getUser().orElseThrow { RuntimeException() }, + ocFile = file, + conflictUploadId = conflictUploadId, + behaviour = "", + packageName = "", + activityName = "", + downloadType = null + ) + } } else { uploadsStorageManager!!.removeUpload(upload) } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index 27ae30f27f45..d11c91f4a22b 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -43,6 +43,8 @@ import com.google.android.material.snackbar.Snackbar; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; +import com.nextcloud.client.files.downloader.FilesDownloadHelper; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.utils.EditorUtils; @@ -54,8 +56,6 @@ import com.owncloud.android.datamodel.ArbitraryDataProvider; import com.owncloud.android.datamodel.ArbitraryDataProviderImpl; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.files.services.FileDownloader; -import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.lib.common.OwnCloudAccount; @@ -166,7 +166,7 @@ public abstract class FileActivity extends DrawerActivity private boolean mResumed; - protected FileDownloaderBinder mDownloaderBinder; + protected FilesDownloadWorker.FileDownloaderBinder mDownloaderBinder; protected FileUploaderBinder mUploaderBinder; private ServiceConnection mDownloadServiceConnection; private ServiceConnection mUploadServiceConnection; @@ -206,6 +206,7 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mHandler = new Handler(); mFileOperationsHelper = new FileOperationsHelper(this, getUserAccountManager(), connectivityService, editorUtils); + User user = null; if (savedInstanceState != null) { mFile = BundleExtensionsKt.getParcelableArgument(savedInstanceState, FileActivity.EXTRA_FILE, OCFile.class); @@ -218,10 +219,11 @@ protected void onCreate(Bundle savedInstanceState) { viewThemeUtils.files.themeActionBar(this, actionBar, savedInstanceState.getString(KEY_ACTION_BAR_TITLE)); } } else { - User user = IntentExtensionsKt.getParcelableArgument(getIntent(), FileActivity.EXTRA_USER, User.class); + user = IntentExtensionsKt.getParcelableArgument(getIntent(), FileActivity.EXTRA_USER, User.class); mFile = IntentExtensionsKt.getParcelableArgument(getIntent(), FileActivity.EXTRA_FILE, OCFile.class); mFromNotification = getIntent().getBooleanExtra(FileActivity.EXTRA_FROM_NOTIFICATION, false); + if (user != null) { setUser(user); } @@ -233,8 +235,8 @@ protected void onCreate(Bundle savedInstanceState) { Context.BIND_AUTO_CREATE); mDownloadServiceConnection = newTransferenceServiceConnection(); - if (mDownloadServiceConnection != null) { - new FileDownloader(new Intent(this, FileDownloader.class)); + if (mDownloadServiceConnection != null && user != null) { + new FilesDownloadHelper().downloadFile(user, mFile, "", null, "", "", null); } mUploadServiceConnection = newTransferenceServiceConnection(); if (mUploadServiceConnection != null) { @@ -615,7 +617,7 @@ public void onServiceDisconnected(ComponentName component) { } @Override - public FileDownloaderBinder getFileDownloaderBinder() { + public FilesDownloadWorker.FileDownloaderBinder getFileDownloaderBinder() { return mDownloaderBinder; } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index b0b23675dcdc..14298e498805 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -65,6 +65,8 @@ import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; import com.nextcloud.client.files.DeepLinkHandler; +import com.nextcloud.client.files.downloader.FilesDownloadHelper; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.client.media.PlayerServiceConnection; import com.nextcloud.client.network.ClientFactory; import com.nextcloud.client.network.ConnectivityService; @@ -80,8 +82,6 @@ import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.VirtualFolderType; -import com.owncloud.android.files.services.FileDownloader; -import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.files.services.NameCollisionPolicy; @@ -684,12 +684,12 @@ protected void refreshDetailsFragmentIfVisible(String downloadEvent, String down // the user browsed to other file ; forget the automatic preview mWaitingToPreview = null; - } else if (downloadEvent.equals(FileDownloader.getDownloadAddedMessage())) { + } else if (downloadEvent.equals(FilesDownloadWorker.Companion.getDownloadAddedMessage())) { // grant that the details fragment updates the progress bar detailsFragment.listenForTransferProgress(); detailsFragment.updateFileDetails(true, false); - } else if (downloadEvent.equals(FileDownloader.getDownloadFinishMessage())) { + } else if (downloadEvent.equals(FilesDownloadWorker.Companion.getDownloadFinishMessage())) { // update the details panel boolean detailsFragmentChanged = false; if (waitedPreview) { @@ -1115,8 +1115,8 @@ protected void onResume() { localBroadcastManager.registerReceiver(mUploadFinishReceiver, uploadIntentFilter); // Listen for download messages - IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.getDownloadAddedMessage()); - downloadIntentFilter.addAction(FileDownloader.getDownloadFinishMessage()); + IntentFilter downloadIntentFilter = new IntentFilter(FilesDownloadWorker.Companion.getDownloadAddedMessage()); + downloadIntentFilter.addAction(FilesDownloadWorker.Companion.getDownloadFinishMessage()); mDownloadFinishReceiver = new DownloadFinishReceiver(); localBroadcastManager.registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); @@ -1417,7 +1417,7 @@ private boolean isAscendant(String linkedToRemotePath) { /** - * Class waiting for broadcast events from the {@link FileDownloader} service. + * Class waiting for broadcast events from the {@link FilesDownloadWorker} service. *

* Updates the UI when a download is started or finished, provided that it is relevant for the current folder. */ @@ -1426,16 +1426,16 @@ private class DownloadFinishReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { boolean sameAccount = isSameAccount(intent); - String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH); + String downloadedRemotePath = intent.getStringExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH); String downloadBehaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); boolean isDescendant = isDescendant(downloadedRemotePath); if (sameAccount && isDescendant) { - String linkedToRemotePath = intent.getStringExtra(FileDownloader.EXTRA_LINKED_TO_PATH); + String linkedToRemotePath = intent.getStringExtra(FilesDownloadWorker.EXTRA_LINKED_TO_PATH); if (linkedToRemotePath == null || isAscendant(linkedToRemotePath)) { updateListOfFilesFragment(false); } - refreshDetailsFragmentIfVisible(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false)); + refreshDetailsFragmentIfVisible(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, false)); } if (mWaitingToSend != null) { @@ -1468,7 +1468,7 @@ private boolean isAscendant(String linkedToRemotePath) { } private boolean isSameAccount(Intent intent) { - String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME); + String accountName = intent.getStringExtra(FilesDownloadWorker.ACCOUNT_NAME); return accountName != null && getAccount() != null && accountName.equals(getAccount().name); } } @@ -1570,9 +1570,9 @@ private class ListServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { - if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) { + if (component.equals(new ComponentName(FileDisplayActivity.this, FilesDownloadWorker.class))) { Log_OC.d(TAG, "Download service connected"); - mDownloaderBinder = (FileDownloaderBinder) service; + mDownloaderBinder = (FilesDownloadWorker.FileDownloaderBinder) service; if (mWaitingToPreview != null && getStorageManager() != null) { // update the file mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); @@ -1603,7 +1603,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { - if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) { + if (component.equals(new ComponentName(FileDisplayActivity.this, FilesDownloadWorker.class))) { Log_OC.d(TAG, "Download service disconnected"); mDownloaderBinder = null; } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { @@ -1885,10 +1885,7 @@ private void requestForDownload() { User user = getUser().orElseThrow(RuntimeException::new); //if (!mWaitingToPreview.isDownloading()) { if (!mDownloaderBinder.isDownloading(user, mWaitingToPreview)) { - Intent i = new Intent(this, FileDownloader.class); - i.putExtra(FileDownloader.EXTRA_USER, user); - i.putExtra(FileDownloader.EXTRA_FILE, mWaitingToPreview); - startService(i); + new FilesDownloadHelper().downloadFile(user, mWaitingToPreview, "", null, "", "", null); } } @@ -1960,13 +1957,7 @@ public void run() { private void requestForDownload(OCFile file, String downloadBehaviour, String packageName, String activityName) { final User currentUser = getUser().orElseThrow(RuntimeException::new); if (!mDownloaderBinder.isDownloading(currentUser, mWaitingToPreview)) { - Intent i = new Intent(this, FileDownloader.class); - i.putExtra(FileDownloader.EXTRA_USER, currentUser); - i.putExtra(FileDownloader.EXTRA_FILE, file); - i.putExtra(SendShareDialog.PACKAGE_NAME, packageName); - i.putExtra(SendShareDialog.ACTIVITY_NAME, activityName); - i.putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, downloadBehaviour); - startService(i); + new FilesDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, null, activityName, packageName, null); } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 0f89b28c66b9..598a8e740772 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -41,6 +41,7 @@ import com.google.common.collect.Sets; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.onboarding.FirstRunActivity; import com.nextcloud.java.util.Optional; @@ -51,7 +52,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.FileDownloader; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.UserInfo; @@ -243,8 +243,8 @@ private boolean hasCurrentAccountChanged() { private void initializeComponentGetters() { downloadServiceConnection = newTransferenceServiceConnection(); if (downloadServiceConnection != null) { - bindService(new Intent(this, FileDownloader.class), downloadServiceConnection, - Context.BIND_AUTO_CREATE); + // FIXME check this usage + // bindService(new Intent(this, FileDownloader.class), downloadServiceConnection, Context.BIND_AUTO_CREATE); } uploadServiceConnection = newTransferenceServiceConnection(); if (uploadServiceConnection != null) { @@ -535,8 +535,8 @@ private class ManageAccountsServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { - if (component.equals(new ComponentName(ManageAccountsActivity.this, FileDownloader.class))) { - mDownloaderBinder = (FileDownloader.FileDownloaderBinder) service; + if (component.equals(new ComponentName(ManageAccountsActivity.this, FilesDownloadWorker.class))) { + mDownloaderBinder = (FilesDownloadWorker.FileDownloaderBinder) service; } else if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service connected"); @@ -546,7 +546,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { - if (component.equals(new ComponentName(ManageAccountsActivity.this, FileDownloader.class))) { + if (component.equals(new ComponentName(ManageAccountsActivity.this, FilesDownloadWorker.class))) { Log_OC.d(TAG, "Download service suddenly disconnected"); mDownloaderBinder = null; } else if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index db1f3e2c0497..6aa4af298815 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -44,6 +44,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ClientFactory; import com.nextcloud.client.network.ConnectivityService; @@ -57,7 +58,6 @@ import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.ThumbnailsCacheManager; -import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; @@ -502,7 +502,7 @@ public void updateFileDetails(OCFile file, User user) { * TODO Remove parameter when the transferring state of files is kept in database. * * @param transferring Flag signaling if the file should be considered as downloading or uploading, although - * {@link FileDownloaderBinder#isDownloading(User, OCFile)} and + * {@link com.nextcloud.client.files.downloader.FilesDownloadWorker.FileDownloaderBinder#isDownloading(User, OCFile)} and * {@link FileUploaderBinder#isUploading(User, OCFile)} return false. * @param refresh If 'true', try to refresh the whole file from the database */ @@ -534,7 +534,7 @@ public void updateFileDetails(boolean transferring, boolean refresh) { setFavoriteIconStatus(file.isFavorite()); // configure UI for depending upon local state of the file - FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); + FilesDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(user, file)) @@ -659,7 +659,7 @@ private void setButtonsForTransferring() { // show the progress bar for the transfer binding.progressBlock.setVisibility(View.VISIBLE); binding.progressText.setVisibility(View.VISIBLE); - FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); + FilesDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); //if (getFile().isDownloading()) { if (downloaderBinder != null && downloaderBinder.isDownloading(user, getFile())) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileFragment.java index 7fed2881dbca..e64dd05f2390 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileFragment.java @@ -27,7 +27,6 @@ import com.nextcloud.utils.extensions.BundleExtensionsKt; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.ui.activity.ComponentsGetter; @@ -161,8 +160,8 @@ public interface ContainerActivity extends ComponentsGetter { * This happens when a download or upload is started or ended for a file. * * This method is necessary by now to update the user interface of the double-pane layout - * in tablets because methods {@link FileDownloaderBinder#isDownloading(Account, OCFile)} - * and {@link FileUploaderBinder#isUploading(Account, OCFile)} + * in tablets because methods {@link //FileDownloaderBinder # isDownloading(Account, OCFile)} + * and {@link FileUploaderBinder# isUploading(Account, OCFile)} * won't provide the needed response before the method where this is called finishes. * * TODO Remove this when the transfer state of a file is kept in the database diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 0e66daa7a429..a3e7411dc2bf 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -47,6 +47,7 @@ import com.nextcloud.client.account.CurrentAccountProvider; import com.nextcloud.client.account.User; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.java.util.Optional; @@ -58,7 +59,6 @@ import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.StreamMediaFileOperation; -import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; @@ -997,7 +997,7 @@ public void cancelTransference(OCFile file) { } // for both files and folders - FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder(); + FilesDownloadWorker.FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder(); if (downloaderBinder != null && downloaderBinder.isDownloading(currentUser, file)) { downloaderBinder.cancel(currentUser.toPlatformAccount(), file); } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 1152562ae92d..e83786b39347 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -37,6 +37,8 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; +import com.nextcloud.client.files.downloader.FilesDownloadHelper; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.java.util.Optional; import com.nextcloud.utils.extensions.IntentExtensionsKt; @@ -45,8 +47,6 @@ import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.VirtualFolderType; -import com.owncloud.android.files.services.FileDownloader; -import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.lib.common.operations.OnRemoteOperationListener; @@ -311,8 +311,8 @@ private class PreviewImageServiceConnection implements ServiceConnection { public void onServiceConnected(ComponentName component, IBinder service) { if (component.equals(new ComponentName(PreviewImageActivity.this, - FileDownloader.class))) { - mDownloaderBinder = (FileDownloaderBinder) service; + FilesDownloadWorker.class))) { + mDownloaderBinder = (FilesDownloadWorker.FileDownloaderBinder) service; if (mRequestWaitingForBinder) { mRequestWaitingForBinder = false; Log_OC.d(TAG, "Simulating reselection of current page after connection " + @@ -331,7 +331,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { if (component.equals(new ComponentName(PreviewImageActivity.this, - FileDownloader.class))) { + FilesDownloadWorker.class))) { Log_OC.d(TAG, "Download service suddenly disconnected"); mDownloaderBinder = null; } else if (component.equals(new ComponentName(PreviewImageActivity.this, @@ -359,7 +359,7 @@ protected void onResume() { super.onResume(); mDownloadFinishReceiver = new DownloadFinishReceiver(); - IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.getDownloadFinishMessage()); + IntentFilter downloadIntentFilter = new IntentFilter(FilesDownloadWorker.Companion.getDownloadFinishMessage()); localBroadcastManager.registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); mUploadFinishReceiver = new UploadFinishReceiver(); @@ -413,13 +413,7 @@ public void requestForDownload(OCFile file, String downloadBehaviour) { } else if (!mDownloaderBinder.isDownloading(getUserAccountManager().getUser(), file)) { final User user = getUser().orElseThrow(RuntimeException::new); - Intent i = new Intent(this, FileDownloader.class); - i.putExtra(FileDownloader.EXTRA_USER, user); - i.putExtra(FileDownloader.EXTRA_FILE, file); - if (downloadBehaviour != null) { - i.putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, downloadBehaviour); - } - new FileDownloader(i); + new FilesDownloadHelper().downloadFile(user, file, downloadBehaviour, null, "", "", null); } } @@ -484,7 +478,7 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse } /** - * Class waiting for broadcast events from the {@link FileDownloader} service. + * Class waiting for broadcast events from the {@link FilesDownloadWorker} service. * * Updates the UI when a download is started or finished, provided that it is relevant for the * folder displayed in the gallery. @@ -504,12 +498,12 @@ public void onReceive(Context context, Intent intent) { } private void previewNewImage(Intent intent) { - String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME); - String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH); + String accountName = intent.getStringExtra(FilesDownloadWorker.ACCOUNT_NAME); + String downloadedRemotePath = intent.getStringExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH); String downloadBehaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); if (getAccount().name.equals(accountName) && downloadedRemotePath != null) { OCFile file = getStorageManager().getFileByPath(downloadedRemotePath); - boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false); + boolean downloadWasFine = intent.getBooleanExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, false); if (EditImageActivity.OPEN_IMAGE_EDITOR.equals(downloadBehaviour)) { startImageEditor(file); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index 2b685b8a8c59..0b98dae862f4 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -53,6 +53,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; +import com.nextcloud.client.files.downloader.FilesDownloadHelper; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.media.ExoplayerListener; import com.nextcloud.client.media.NextcloudExoPlayer; @@ -66,7 +67,6 @@ import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.ThumbnailsCacheManager; import com.owncloud.android.files.StreamMediaFileOperation; -import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; @@ -479,10 +479,7 @@ public void onFileActionChosen(final int itemId) { backgroundJobManager); } else if (itemId == R.id.action_download_file) { if (!containerActivity.getFileDownloaderBinder().isDownloading(user, getFile())) { - Intent i = new Intent(requireActivity(), FileDownloader.class); - i.putExtra(FileDownloader.EXTRA_USER, user); - i.putExtra(FileDownloader.EXTRA_FILE, getFile()); - new FileDownloader(i); + new FilesDownloadHelper().downloadFile(user, getFile(), "", null, "", "", null); } } } From 828c239a9757177d3748d5a175a23abcf564ae30 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 12:34:41 +0100 Subject: [PATCH 008/189] Overload downloadFile functions Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadHelper.kt | 48 +++++++++++++++++++ .../nextcloud/client/jobs/FilesExportWork.kt | 6 +-- .../operations/SynchronizeFileOperation.java | 7 +-- .../SynchronizeFolderOperation.java | 9 +--- .../ui/activity/ConflictsResolveActivity.kt | 10 ++-- .../android/ui/activity/FileActivity.java | 2 +- .../ui/activity/FileDisplayActivity.java | 2 +- .../ui/preview/PreviewImageActivity.java | 2 +- .../ui/preview/PreviewMediaFragment.java | 2 +- 9 files changed, 58 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt index 71f833c07bdc..8a0a855f84b5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt @@ -41,6 +41,54 @@ class FilesDownloadHelper { MainApp.getAppComponent().inject(this) } + fun downloadFile(user: User, ocFile: OCFile) { + backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + "", + null, + "", + "", + null + ) + } + + fun downloadFile(user: User, ocFile: OCFile, behaviour: String) { + backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + behaviour, + null, + "", + "", + null + ) + } + + fun downloadFile(user: User, ocFile: OCFile, downloadType: DownloadType) { + backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + "", + downloadType, + "", + "", + null + ) + } + + fun downloadFile(user: User, ocFile: OCFile, conflictUploadId: Long) { + backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + "", + null, + "", + "", + conflictUploadId + ) + } + fun downloadFile( user: User, ocFile: OCFile, diff --git a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt index 60d9eb16beb0..797cea1969e4 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt @@ -114,11 +114,7 @@ class FilesExportWork( FilesDownloadHelper().downloadFile( user, ocFile, - behaviour = "", - packageName = "", - activityName = "", - conflictUploadId = 0L, - downloadType = DownloadType.EXPORT + DownloadType.EXPORT ) } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java index 4efa2c0b7841..1d9228dab52d 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -320,12 +320,7 @@ private void requestForDownload(OCFile file) { downloadHelper.downloadFile( mUser, - file, - "", - null, - "", - "", - null); + file); mTransferWasRequested = true; } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index 5bfd7ad0dc0d..8aa1e07a765e 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -454,14 +454,7 @@ private void startDirectDownloads() throws OperationCancelledException { FilesDownloadHelper downloadHelper = new FilesDownloadHelper(); - downloadHelper.downloadFile( - user, - file, - "", - null, - "", - "", - null); + downloadHelper.downloadFile(user, file); } } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt index 4ac180376a21..5d18e9698380 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt @@ -116,13 +116,9 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener // Overwrite local file file?.let { FilesDownloadHelper().downloadFile( - user = getUser().orElseThrow { RuntimeException() }, - ocFile = file, - conflictUploadId = conflictUploadId, - behaviour = "", - packageName = "", - activityName = "", - downloadType = null + getUser().orElseThrow { RuntimeException() }, + file, + conflictUploadId ) } } else { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index d11c91f4a22b..2a89b567e764 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -236,7 +236,7 @@ protected void onCreate(Bundle savedInstanceState) { mDownloadServiceConnection = newTransferenceServiceConnection(); if (mDownloadServiceConnection != null && user != null) { - new FilesDownloadHelper().downloadFile(user, mFile, "", null, "", "", null); + new FilesDownloadHelper().downloadFile(user, mFile); } mUploadServiceConnection = newTransferenceServiceConnection(); if (mUploadServiceConnection != null) { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 14298e498805..106dac2e027e 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1885,7 +1885,7 @@ private void requestForDownload() { User user = getUser().orElseThrow(RuntimeException::new); //if (!mWaitingToPreview.isDownloading()) { if (!mDownloaderBinder.isDownloading(user, mWaitingToPreview)) { - new FilesDownloadHelper().downloadFile(user, mWaitingToPreview, "", null, "", "", null); + new FilesDownloadHelper().downloadFile(user, mWaitingToPreview); } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index e83786b39347..fe11f92933fc 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -413,7 +413,7 @@ public void requestForDownload(OCFile file, String downloadBehaviour) { } else if (!mDownloaderBinder.isDownloading(getUserAccountManager().getUser(), file)) { final User user = getUser().orElseThrow(RuntimeException::new); - new FilesDownloadHelper().downloadFile(user, file, downloadBehaviour, null, "", "", null); + new FilesDownloadHelper().downloadFile(user, file, downloadBehaviour); } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index 0b98dae862f4..d42ebb0255cc 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -479,7 +479,7 @@ public void onFileActionChosen(final int itemId) { backgroundJobManager); } else if (itemId == R.id.action_download_file) { if (!containerActivity.getFileDownloaderBinder().isDownloading(user, getFile())) { - new FilesDownloadHelper().downloadFile(user, getFile(), "", null, "", "", null); + new FilesDownloadHelper().downloadFile(user, getFile()); } } } From f0a845fc3a70e061d73d163eca17449b4b98f97c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 15:23:34 +0100 Subject: [PATCH 009/189] Overload downloadFile functions Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 29 +++++++++++++++---- .../client/jobs/BackgroundJobManagerImpl.kt | 12 ++++++-- .../android/operations/DownloadType.kt | 10 +++++-- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index dfdf51781a96..123f94fae438 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -41,6 +41,10 @@ import androidx.core.app.NotificationCompat import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters +import com.google.gson.Gson +import com.google.gson.JsonElement +import com.google.gson.JsonSerializationContext +import com.google.gson.JsonSerializer import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional @@ -86,6 +90,8 @@ class FilesDownloadWorker( companion object { private val TAG = FilesDownloadWorker::class.java.simpleName + + var user: User? = null const val USER = "USER" const val FILE = "FILE" const val BEHAVIOUR = "BEHAVIOUR" @@ -122,13 +128,22 @@ class FilesDownloadWorker( private var startedDownload = false private var storageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null + private val gson = Gson() override fun doWork(): Result { return try { - conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long - val user = inputData.keyValueMap[USER] as User - val file = inputData.keyValueMap[FILE] as OCFile - val downloadType = inputData.keyValueMap[DOWNLOAD_TYPE] as DownloadType + conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? + val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) + val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? + val downloadType = if (downloadTypeAsString != null) { + if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { + DownloadType.DOWNLOAD + } else { + DownloadType.EXPORT + } + } else { + null + } val behaviour = inputData.keyValueMap[BEHAVIOUR] as String val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String val packageName = inputData.keyValueMap[PACKAGE_NAME] as String @@ -137,10 +152,12 @@ class FilesDownloadWorker( showDownloadingFilesNotification() addAccountUpdateListener() - requestDownloads(user, file, behaviour, downloadType, activityName, packageName) + requestDownloads(user!!, file, behaviour, downloadType, activityName, packageName) + Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() } catch (t: Throwable) { + Log_OC.e(TAG, "Error caught at FilesDownloadWorker(): " + t.localizedMessage) Result.failure() } } @@ -149,7 +166,7 @@ class FilesDownloadWorker( user: User, file: OCFile, behaviour: String, - downloadType: DownloadType, + downloadType: DownloadType?, activityName: String, packageName: String, ) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 943e9c6d0fc3..249542077afd 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -34,6 +34,7 @@ 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 @@ -517,16 +518,21 @@ internal class BackgroundJobManagerImpl( packageName: String, conflictUploadId: Long? ) { + val gson = Gson() + + // FIXME user interface cant serialize and deserialize val data = workDataOf( - FilesDownloadWorker.USER to user, - FilesDownloadWorker.FILE to ocFile, + //FilesDownloadWorker.USER to gson.toJson(user), + FilesDownloadWorker.FILE to gson.toJson(ocFile), FilesDownloadWorker.BEHAVIOUR to behaviour, - FilesDownloadWorker.DOWNLOAD_TYPE to downloadType, + FilesDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), FilesDownloadWorker.ACTIVITY_NAME to activityName, FilesDownloadWorker.PACKAGE_NAME to packageName, FilesDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId, ) + FilesDownloadWorker.user = user + val request = oneTimeRequestBuilder(FilesDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .setInputData(data) .build() diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadType.kt b/app/src/main/java/com/owncloud/android/operations/DownloadType.kt index c1a28d7ba32b..c38a6999631c 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadType.kt +++ b/app/src/main/java/com/owncloud/android/operations/DownloadType.kt @@ -22,7 +22,11 @@ package com.owncloud.android.operations -enum class DownloadType { - DOWNLOAD, - EXPORT +enum class DownloadType(var type: String) { + DOWNLOAD("DOWNLOAD"), + EXPORT("EXPORT"); + + override fun toString(): String { + return type + } } From 8610275362bb25670165879a79e2f5336fd1daaa Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 15:43:00 +0100 Subject: [PATCH 010/189] Remove handler Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 179 +++++++----------- .../ui/activity/ManageAccountsActivity.java | 4 +- .../ui/fragment/FileDetailFragment.java | 4 +- .../ui/helpers/FileOperationsHelper.java | 2 +- .../ui/preview/FileDownloadFragment.java | 4 +- 5 files changed, 72 insertions(+), 121 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index 123f94fae438..787bcb4f10ff 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -32,19 +32,13 @@ import android.content.Intent import android.graphics.BitmapFactory import android.os.Binder import android.os.Build -import android.os.Handler import android.os.IBinder -import android.os.Looper -import android.os.Message import android.util.Pair import androidx.core.app.NotificationCompat import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters import com.google.gson.Gson -import com.google.gson.JsonElement -import com.google.gson.JsonSerializationContext -import com.google.gson.JsonSerializer import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional @@ -124,7 +118,6 @@ class FilesDownloadWorker( private val pendingDownloads = IndexedForest() private var downloadBinder: IBinder? = null private var currentUser = Optional.empty() - private val workerHandler: WorkerHandler? = null private var startedDownload = false private var storageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null @@ -132,27 +125,16 @@ class FilesDownloadWorker( override fun doWork(): Result { return try { - conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? - val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) - val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? - val downloadType = if (downloadTypeAsString != null) { - if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { - DownloadType.DOWNLOAD - } else { - DownloadType.EXPORT - } - } else { - null - } - val behaviour = inputData.keyValueMap[BEHAVIOUR] as String - val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String - val packageName = inputData.keyValueMap[PACKAGE_NAME] as String - - downloadBinder = FileDownloaderBinder() + val requestDownloads = getRequestDownloads() showDownloadingFilesNotification() addAccountUpdateListener() - requestDownloads(user!!, file, behaviour, downloadType, activityName, packageName) + + val it: Iterator = requestDownloads.iterator() + while (it.hasNext()) { + val next = it.next() + downloadFile(next) + } Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() @@ -162,14 +144,23 @@ class FilesDownloadWorker( } } - private fun requestDownloads( - user: User, - file: OCFile, - behaviour: String, - downloadType: DownloadType?, - activityName: String, - packageName: String, - ) { + private fun getRequestDownloads(): AbstractList { + conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? + val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) + val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? + val downloadType = if (downloadTypeAsString != null) { + if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { + DownloadType.DOWNLOAD + } else { + DownloadType.EXPORT + } + } else { + null + } + val behaviour = inputData.keyValueMap[BEHAVIOUR] as String + val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String + val packageName = inputData.keyValueMap[PACKAGE_NAME] as String + val requestedDownloads: AbstractList = Vector() try { val operation = DownloadFileOperation( @@ -184,7 +175,7 @@ class FilesDownloadWorker( operation.addDatatransferProgressListener(this) operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder?) val putResult: Pair = pendingDownloads.putIfAbsent( - user.accountName, + user?.accountName, file.remotePath, operation ) @@ -196,15 +187,7 @@ class FilesDownloadWorker( Log_OC.e(TAG, "Not enough information provided in intent: " + e.message) } - if (requestedDownloads.size > 0) { - val msg: Message? = workerHandler?.obtainMessage() - // msg.arg1 = startId; - msg?.obj = requestedDownloads - - msg?.let { - workerHandler?.sendMessage(msg) - } - } + return requestedDownloads } private fun downloadFile(downloadKey: String) { @@ -266,16 +249,24 @@ class FilesDownloadWorker( } } - private fun saveDownloadedFile() { + private fun getCurrentFile(): OCFile? { var file: OCFile? = currentDownload?.file?.fileId?.let { storageManager?.getFileById(it) } + if (file == null) { - // try to get file via path, needed for overwriting existing files on conflict dialog file = storageManager?.getFileByDecryptedRemotePath(currentDownload?.file?.remotePath) } + if (file == null) { Log_OC.e(this, "Could not save " + currentDownload?.file?.remotePath) - return + return null } + + return file + } + + private fun saveDownloadedFile() { + val file = getCurrentFile() ?: return + val syncDate = System.currentTimeMillis() file.lastSyncDateForProperties = syncDate file.lastSyncDateForData = syncDate @@ -325,10 +316,12 @@ class FilesDownloadWorker( if (!downloadResult.isCancelled) { if (downloadResult.isSuccess) { - if (conflictUploadId!! > 0) { - uploadsStorageManager.removeUpload(conflictUploadId!!) + conflictUploadId?.let { + if (it > 0) { + uploadsStorageManager.removeUpload(it) + } } - // Dont show notification except an error has occured. + return } var tickerId = @@ -363,14 +356,12 @@ class FilesDownloadWorker( ) ) - if (notificationManager != null) { - notificationManager?.notify(SecureRandom().nextInt(), notificationBuilder?.build()) - if (downloadResult.isSuccess) { - NotificationUtils.cancelWithDelay( - notificationManager, - R.string.downloader_download_succeeded_ticker, 2000 - ) - } + notificationManager?.notify(SecureRandom().nextInt(), notificationBuilder?.build()) + if (downloadResult.isSuccess) { + NotificationUtils.cancelWithDelay( + notificationManager, + R.string.downloader_download_succeeded_ticker, 2000 + ) } } } @@ -432,9 +423,8 @@ class FilesDownloadWorker( if (notificationManager == null) { notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager } - if (notificationManager != null) { - notificationManager?.notify(R.string.downloader_download_in_progress_ticker, notificationBuilder?.build()) - } + + notificationManager?.notify(R.string.downloader_download_in_progress_ticker, notificationBuilder?.build()) } private fun showDownloadingFilesNotification() { @@ -474,7 +464,7 @@ class FilesDownloadWorker( } override fun onAccountsUpdated(accounts: Array?) { - if (currentDownload != null && !accountManager.exists(currentDownload?.user?.toPlatformAccount())) { + if (!accountManager.exists(currentDownload?.user?.toPlatformAccount())) { currentDownload?.cancel() } } @@ -496,31 +486,18 @@ class FilesDownloadWorker( if (notificationManager == null) { notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager } - if (notificationManager != null) { - notificationManager?.notify( - R.string.downloader_download_in_progress_ticker, - notificationBuilder?.build() - ) - } + notificationManager?.notify( + R.string.downloader_download_in_progress_ticker, + notificationBuilder?.build() + ) } lastPercent = percent } inner class FileDownloaderBinder : Binder(), OnDatatransferProgressListener { - /** - * Map of listeners that will be reported about progress of downloads from a - * [FileDownloaderBinder] - * instance. - */ - private val mBoundListeners: MutableMap = HashMap() - - /** - * Cancels a pending or current download of a remote file. - * - * @param account ownCloud account where the remote file is stored. - * @param file A file in the queue of pending downloads - */ - fun cancel(account: Account, file: OCFile) { + private val boundListeners: MutableMap = HashMap() + + fun cancelPendingOrCurrentDownloads(account: Account, file: OCFile) { val removeResult: Pair = pendingDownloads.remove(account.name, file.remotePath) val download = removeResult.first @@ -535,10 +512,7 @@ class FilesDownloadWorker( } } - /** - * Cancels all the downloads for an account - */ - fun cancel(accountName: String?) { + fun cancelAllDownloadsForAccount(accountName: String?) { if (currentDownload != null && currentDownload?.user?.nameEquals(accountName) == true) { currentDownload?.cancel() } @@ -550,20 +524,20 @@ class FilesDownloadWorker( return user != null && file != null && pendingDownloads.contains(user.accountName, file.remotePath) } - fun addDatatransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { + fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { if (file == null || listener == null) { return } - mBoundListeners[file.fileId] = listener + boundListeners[file.fileId] = listener } - fun removeDatatransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { + fun removeDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { if (file == null || listener == null) { return } val fileId = file.fileId - if (mBoundListeners[fileId] === listener) { - mBoundListeners.remove(fileId) + if (boundListeners[fileId] === listener) { + boundListeners.remove(fileId) } } @@ -571,34 +545,11 @@ class FilesDownloadWorker( progressRate: Long, totalTransferredSoFar: Long, totalToTransfer: Long, fileName: String ) { - val boundListener = mBoundListeners[currentDownload?.file?.fileId] + val boundListener = boundListeners[currentDownload?.file?.fileId] boundListener?.onTransferProgress( progressRate, totalTransferredSoFar, totalToTransfer, fileName ) } } - - private class WorkerHandler(looper: Looper, private val worker: FilesDownloadWorker) : Handler(looper) { - override fun handleMessage(msg: Message) { - val requestedDownloads = msg.obj as AbstractList - - if (msg.obj != null) { - val it: Iterator = requestedDownloads.iterator() - while (it.hasNext()) { - val next = it.next() - worker.downloadFile(next) - } - } - - worker.startedDownload = false - - Handler(Looper.getMainLooper()).postDelayed({ - if (!worker.startedDownload) { - worker.notificationManager?.cancel(R.string.downloader_download_in_progress_ticker) - } - Log_OC.d(TAG, "Stopping after command with id " + msg.arg1) - }, 2000) - } - } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 598a8e740772..1cd495dfee49 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -341,7 +341,7 @@ public void run(AccountManagerFuture future) { mUploaderBinder.cancel(accountName); } if (mDownloaderBinder != null) { - mDownloaderBinder.cancel(accountName); + mDownloaderBinder.cancelAllDownloadsForAccount(accountName); } } @@ -436,7 +436,7 @@ private void performAccountRemoval(User user) { mUploaderBinder.cancel(user); } if (mDownloaderBinder != null) { - mDownloaderBinder.cancel(user.getAccountName()); + mDownloaderBinder.cancelAllDownloadsForAccount(user.getAccountName()); } backgroundJobManager.startAccountRemovalJob(user.getAccountName(), false); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 6aa4af298815..9f16f82dd003 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -696,7 +696,7 @@ public void listenForTransferProgress() { if (progressListener != null) { if (containerActivity.getFileDownloaderBinder() != null) { containerActivity.getFileDownloaderBinder(). - addDatatransferProgressListener(progressListener, getFile()); + addDataTransferProgressListener(progressListener, getFile()); } if (containerActivity.getFileUploaderBinder() != null) { containerActivity.getFileUploaderBinder(). @@ -711,7 +711,7 @@ private void leaveTransferProgress() { if (progressListener != null) { if (containerActivity.getFileDownloaderBinder() != null) { containerActivity.getFileDownloaderBinder(). - removeDatatransferProgressListener(progressListener, getFile()); + removeDataTransferProgressListener(progressListener, getFile()); } if (containerActivity.getFileUploaderBinder() != null) { containerActivity.getFileUploaderBinder(). diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index a3e7411dc2bf..8700a80c61f1 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -999,7 +999,7 @@ public void cancelTransference(OCFile file) { // for both files and folders FilesDownloadWorker.FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder(); if (downloaderBinder != null && downloaderBinder.isDownloading(currentUser, file)) { - downloaderBinder.cancel(currentUser.toPlatformAccount(), file); + downloaderBinder.cancelPendingOrCurrentDownloads(currentUser.toPlatformAccount(), file); } FileUploaderBinder uploaderBinder = fileActivity.getFileUploaderBinder(); if (uploaderBinder != null && uploaderBinder.isUploading(currentUser, file)) { diff --git a/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java index 37272639fcd9..d7c05e595409 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java @@ -262,7 +262,7 @@ private void setButtonsForRemote() { public void listenForTransferProgress() { if (mProgressListener != null && !mListening && containerActivity.getFileDownloaderBinder() != null) { - containerActivity.getFileDownloaderBinder().addDatatransferProgressListener(mProgressListener, getFile()); + containerActivity.getFileDownloaderBinder().addDataTransferProgressListener(mProgressListener, getFile()); mListening = true; setButtonsForTransferring(); } @@ -272,7 +272,7 @@ public void listenForTransferProgress() { public void leaveTransferProgress() { if (mProgressListener != null && containerActivity.getFileDownloaderBinder() != null) { containerActivity.getFileDownloaderBinder() - .removeDatatransferProgressListener(mProgressListener, getFile()); + .removeDataTransferProgressListener(mProgressListener, getFile()); mListening = false; } } From 2b595910b463c4848e76a3f4864fbce4bcc96769 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 16:28:37 +0100 Subject: [PATCH 011/189] Use interfaceSerializer Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 12 +++- .../client/jobs/BackgroundJobManagerImpl.kt | 5 +- .../nextcloud/utils/InterfaceSerializer.java | 56 +++++++++++++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index 787bcb4f10ff..d81c61358b80 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -39,9 +39,12 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters import com.google.gson.Gson +import com.google.gson.GsonBuilder import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional +import com.nextcloud.utils.InterfaceSerializer +import com.nextcloud.utils.InterfaceSerializer.interfaceSerializer import com.owncloud.android.R import com.owncloud.android.authentication.AuthenticatorActivity import com.owncloud.android.datamodel.FileDataStorageManager @@ -85,7 +88,6 @@ class FilesDownloadWorker( companion object { private val TAG = FilesDownloadWorker::class.java.simpleName - var user: User? = null const val USER = "USER" const val FILE = "FILE" const val BEHAVIOUR = "BEHAVIOUR" @@ -144,9 +146,17 @@ class FilesDownloadWorker( } } + // FIXME stackoverflow + private fun getUserGson(): Gson { + return GsonBuilder() + .registerTypeAdapter(User::class.java, interfaceSerializer(User::class.java)) + .create() + } + private fun getRequestDownloads(): AbstractList { conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) + val user = getUserGson().fromJson(inputData.keyValueMap[USER] as String, User::class.java) val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? val downloadType = if (downloadTypeAsString != null) { if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 249542077afd..e1ea1a2957d4 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -520,9 +520,8 @@ internal class BackgroundJobManagerImpl( ) { val gson = Gson() - // FIXME user interface cant serialize and deserialize val data = workDataOf( - //FilesDownloadWorker.USER to gson.toJson(user), + FilesDownloadWorker.USER to gson.toJson(user), FilesDownloadWorker.FILE to gson.toJson(ocFile), FilesDownloadWorker.BEHAVIOUR to behaviour, FilesDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), @@ -531,8 +530,6 @@ internal class BackgroundJobManagerImpl( FilesDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId, ) - FilesDownloadWorker.user = user - val request = oneTimeRequestBuilder(FilesDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .setInputData(data) .build() diff --git a/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java b/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java new file mode 100644 index 000000000000..da253c14d9b5 --- /dev/null +++ b/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java @@ -0,0 +1,56 @@ +/* + * 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 . + */ + +package com.nextcloud.utils; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +import java.lang.reflect.Type; + +final public class InterfaceSerializer implements JsonSerializer, JsonDeserializer { + + private final Class implementationClass; + + private InterfaceSerializer(final Class implementationClass) { + this.implementationClass = implementationClass; + } + + public static InterfaceSerializer interfaceSerializer(final Class implementationClass) { + return new InterfaceSerializer<>(implementationClass); + } + + @Override + public JsonElement serialize(final T value, final Type type, final JsonSerializationContext context) { + final Type targetType = value != null + ? value.getClass() + : type; + return context.serialize(value, targetType); + } + + @Override + public T deserialize(final JsonElement jsonElement, final Type typeOfT, final JsonDeserializationContext context) { + return context.deserialize(jsonElement, implementationClass); + } +} From 9f3e61cef355f96bb5554e6cb01e418cf8c99b6a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 20 Dec 2023 09:13:15 +0100 Subject: [PATCH 012/189] Create user from accountName Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 15 +---- .../client/jobs/BackgroundJobManagerImpl.kt | 2 +- .../nextcloud/utils/InterfaceSerializer.java | 56 ------------------- 3 files changed, 4 insertions(+), 69 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index d81c61358b80..2b76379698fd 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -39,12 +39,9 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters import com.google.gson.Gson -import com.google.gson.GsonBuilder import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional -import com.nextcloud.utils.InterfaceSerializer -import com.nextcloud.utils.InterfaceSerializer.interfaceSerializer import com.owncloud.android.R import com.owncloud.android.authentication.AuthenticatorActivity import com.owncloud.android.datamodel.FileDataStorageManager @@ -88,7 +85,7 @@ class FilesDownloadWorker( companion object { private val TAG = FilesDownloadWorker::class.java.simpleName - const val USER = "USER" + const val USER_NAME = "USER" const val FILE = "FILE" const val BEHAVIOUR = "BEHAVIOUR" const val DOWNLOAD_TYPE = "DOWNLOAD_TYPE" @@ -146,17 +143,11 @@ class FilesDownloadWorker( } } - // FIXME stackoverflow - private fun getUserGson(): Gson { - return GsonBuilder() - .registerTypeAdapter(User::class.java, interfaceSerializer(User::class.java)) - .create() - } - private fun getRequestDownloads(): AbstractList { conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) - val user = getUserGson().fromJson(inputData.keyValueMap[USER] as String, User::class.java) + val accountName = inputData.keyValueMap[USER_NAME] as String + val user = accountManager.getUser(accountName).get() val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? val downloadType = if (downloadTypeAsString != null) { if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index e1ea1a2957d4..bad195010b08 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -521,7 +521,7 @@ internal class BackgroundJobManagerImpl( val gson = Gson() val data = workDataOf( - FilesDownloadWorker.USER to gson.toJson(user), + FilesDownloadWorker.USER_NAME to user.accountName, FilesDownloadWorker.FILE to gson.toJson(ocFile), FilesDownloadWorker.BEHAVIOUR to behaviour, FilesDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), diff --git a/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java b/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java deleted file mode 100644 index da253c14d9b5..000000000000 --- a/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java +++ /dev/null @@ -1,56 +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 . - */ - -package com.nextcloud.utils; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; - -import java.lang.reflect.Type; - -final public class InterfaceSerializer implements JsonSerializer, JsonDeserializer { - - private final Class implementationClass; - - private InterfaceSerializer(final Class implementationClass) { - this.implementationClass = implementationClass; - } - - public static InterfaceSerializer interfaceSerializer(final Class implementationClass) { - return new InterfaceSerializer<>(implementationClass); - } - - @Override - public JsonElement serialize(final T value, final Type type, final JsonSerializationContext context) { - final Type targetType = value != null - ? value.getClass() - : type; - return context.serialize(value, targetType); - } - - @Override - public T deserialize(final JsonElement jsonElement, final Type typeOfT, final JsonDeserializationContext context) { - return context.deserialize(jsonElement, implementationClass); - } -} From fd3408b9ce09f4539fc0661b03ad9304e5279312 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 20 Dec 2023 09:46:36 +0100 Subject: [PATCH 013/189] Code cleanup Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 271 ++++++++++-------- 1 file changed, 149 insertions(+), 122 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index 2b76379698fd..fa0de11d9e74 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -132,6 +132,7 @@ class FilesDownloadWorker( val it: Iterator = requestDownloads.iterator() while (it.hasNext()) { val next = it.next() + Log_OC.e(TAG, "Download Key: $next") downloadFile(next) } @@ -175,7 +176,7 @@ class FilesDownloadWorker( ) operation.addDatatransferProgressListener(this) operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder?) - val putResult: Pair = pendingDownloads.putIfAbsent( + val putResult = pendingDownloads.putIfAbsent( user?.accountName, file.remotePath, operation @@ -235,18 +236,15 @@ class FilesDownloadWorker( } private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { - var downloadResult = result - val removeResult: Pair = pendingDownloads.removePayload( + val removeResult = pendingDownloads.removePayload( currentDownload?.user?.accountName, currentDownload?.remotePath ) - if (downloadResult == null) { - downloadResult = RemoteOperationResult(RuntimeException("Error downloading…")) - } + val downloadResult = result ?: RemoteOperationResult(RuntimeException("Error downloading…")) - currentDownload?.let { - notifyDownloadResult(it, downloadResult) - sendBroadcastDownloadFinished(it, downloadResult, removeResult.second) + currentDownload?.run { + notifyDownloadResult(this, downloadResult) + sendBroadcastDownloadFinished(this, downloadResult, removeResult.second) } } @@ -269,16 +267,25 @@ class FilesDownloadWorker( val file = getCurrentFile() ?: return val syncDate = System.currentTimeMillis() - file.lastSyncDateForProperties = syncDate - file.lastSyncDateForData = syncDate - file.isUpdateThumbnailNeeded = true - file.modificationTimestamp = currentDownload?.modificationTimestamp ?: 0L - file.modificationTimestampAtLastSyncForData = currentDownload?.modificationTimestamp ?: 0L - file.etag = currentDownload?.etag - file.mimeType = currentDownload?.mimeType - file.storagePath = currentDownload?.savePath - file.fileLength = File(currentDownload?.getSavePath()).length() - file.remoteId = currentDownload?.file?.remoteId + + file.apply { + lastSyncDateForProperties = syncDate + lastSyncDateForData = syncDate + isUpdateThumbnailNeeded = true + modificationTimestamp = currentDownload?.modificationTimestamp ?: 0L + modificationTimestampAtLastSyncForData = currentDownload?.modificationTimestamp ?: 0L + etag = currentDownload?.etag + mimeType = currentDownload?.mimeType + storagePath = currentDownload?.savePath + + val savePathFile = currentDownload?.savePath?.let { File(it) } + savePathFile?.let { + fileLength = savePathFile.length() + } + + remoteId = currentDownload?.file?.remoteId + } + storageManager?.saveFile(file) if (MimeTypeUtil.isMedia(currentDownload?.mimeType)) { @@ -293,18 +300,20 @@ class FilesDownloadWorker( downloadResult: RemoteOperationResult<*>, unlinkedFromRemotePath: String? ) { - val end = Intent(getDownloadFinishMessage()) - end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) - end.putExtra(ACCOUNT_NAME, download.user.accountName) - end.putExtra(EXTRA_REMOTE_PATH, download.remotePath) - end.putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) - end.putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) - end.putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) - if (unlinkedFromRemotePath != null) { - end.putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) - } - end.setPackage(context.packageName) - localBroadcastManager.sendBroadcast(end) + val intent = Intent(getDownloadFinishMessage()).apply { + putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) + putExtra(ACCOUNT_NAME, download.user.accountName) + putExtra(EXTRA_REMOTE_PATH, download.remotePath) + putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) + putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) + putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) + if (unlinkedFromRemotePath != null) { + putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) + } + setPackage(context.packageName) + } + + localBroadcastManager.sendBroadcast(intent) } private fun notifyDownloadResult( @@ -315,72 +324,71 @@ class FilesDownloadWorker( notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager } - if (!downloadResult.isCancelled) { - if (downloadResult.isSuccess) { - conflictUploadId?.let { - if (it > 0) { - uploadsStorageManager.removeUpload(it) - } - } + if (downloadResult.isCancelled) { + return + } - return - } - var tickerId = - if (downloadResult.isSuccess) R.string.downloader_download_succeeded_ticker else R.string.downloader_download_failed_ticker - val needsToUpdateCredentials = ResultCode.UNAUTHORIZED == downloadResult.code - tickerId = if (needsToUpdateCredentials) R.string.downloader_download_failed_credentials_error else tickerId - - notificationBuilder - ?.setTicker(context.getString(tickerId)) - ?.setContentTitle(context.getString(tickerId)) - ?.setAutoCancel(true) - ?.setOngoing(false) - ?.setProgress(0, 0, false) - - if (needsToUpdateCredentials) { - configureUpdateCredentialsNotification(download.user) - } else { - // TODO put something smart in showDetailsIntent - val showDetailsIntent = Intent() - notificationBuilder?.setContentIntent( - PendingIntent.getActivity( - context, System.currentTimeMillis().toInt(), - showDetailsIntent, PendingIntent.FLAG_IMMUTABLE - ) - ) + if (downloadResult.isSuccess) { + conflictUploadId?.let { + if (it > 0) { + uploadsStorageManager.removeUpload(it) + } } - notificationBuilder?.setContentText( - ErrorMessageAdapter.getErrorCauseMessage( - downloadResult, - download, context.resources - ) + return + } + + var tickerId = + if (downloadResult.isSuccess) R.string.downloader_download_succeeded_ticker else R.string.downloader_download_failed_ticker + val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) + tickerId = if (needsToUpdateCredentials) R.string.downloader_download_failed_credentials_error else tickerId + + notificationBuilder + ?.setTicker(context.getString(tickerId)) + ?.setContentTitle(context.getString(tickerId)) + ?.setAutoCancel(true) + ?.setOngoing(false) + ?.setProgress(0, 0, false) + + if (needsToUpdateCredentials) { + configureUpdateCredentialsNotification(download.user) + } else { + showDetailsIntent(null) + } + + notificationBuilder?.setContentText( + ErrorMessageAdapter.getErrorCauseMessage( + downloadResult, + download, context.resources ) + ) - notificationManager?.notify(SecureRandom().nextInt(), notificationBuilder?.build()) - if (downloadResult.isSuccess) { - NotificationUtils.cancelWithDelay( - notificationManager, - R.string.downloader_download_succeeded_ticker, 2000 - ) - } + notificationManager?.notify(SecureRandom().nextInt(), notificationBuilder?.build()) + + if (downloadResult.isSuccess) { + NotificationUtils.cancelWithDelay( + notificationManager, + R.string.downloader_download_succeeded_ticker, 2000 + ) } } private fun configureUpdateCredentialsNotification(user: User) { - val updateAccountCredentials = Intent(context, AuthenticatorActivity::class.java) - updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) - updateAccountCredentials.putExtra( - AuthenticatorActivity.EXTRA_ACTION, - AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN - ) - updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) - updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND) + val intent = Intent(context, AuthenticatorActivity::class.java).apply { + putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) + putExtra( + AuthenticatorActivity.EXTRA_ACTION, + AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN + ) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + addFlags(Intent.FLAG_FROM_BACKGROUND) + } + notificationBuilder?.setContentIntent( PendingIntent.getActivity( context, System.currentTimeMillis().toInt(), - updateAccountCredentials, + intent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE ) ) @@ -400,32 +408,38 @@ class FilesDownloadWorker( File(download.savePath).name ) ) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { notificationBuilder?.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) } - /// includes a pending intent in the notification showing the details view of the file - var showDetailsIntent: Intent? = null - showDetailsIntent = if (PreviewImageFragment.canBePreviewed(download.file)) { - Intent(context, PreviewImageActivity::class.java) + showDetailsIntent(download) + notifyDownloadInProgressNotification() + } + + private fun showDetailsIntent(operation: DownloadFileOperation?) { + val intent: Intent = if (operation != null) { + if (PreviewImageFragment.canBePreviewed(operation.file)) { + Intent(context, PreviewImageActivity::class.java) + } else { + Intent(context, FileDisplayActivity::class.java) + }.apply { + putExtra(FileActivity.EXTRA_FILE, operation.file) + putExtra(FileActivity.EXTRA_USER, operation.user) + flags = Intent.FLAG_ACTIVITY_CLEAR_TOP + } } else { - Intent(context, FileDisplayActivity::class.java) + Intent() } - showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, download.file) - showDetailsIntent.putExtra(FileActivity.EXTRA_USER, download.user) - showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + notificationBuilder?.setContentIntent( PendingIntent.getActivity( - context, System.currentTimeMillis().toInt(), - showDetailsIntent, PendingIntent.FLAG_IMMUTABLE + context, + System.currentTimeMillis().toInt(), + intent, + PendingIntent.FLAG_IMMUTABLE ) ) - - if (notificationManager == null) { - notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - } - - notificationManager?.notify(R.string.downloader_download_in_progress_ticker, notificationBuilder?.build()) } private fun showDownloadingFilesNotification() { @@ -435,7 +449,6 @@ class FilesDownloadWorker( .setSmallIcon(R.drawable.notification_icon) .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { builder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) } @@ -456,12 +469,14 @@ class FilesDownloadWorker( download: DownloadFileOperation, linkedToRemotePath: String ) { - val added = Intent(getDownloadAddedMessage()) - added.putExtra(ACCOUNT_NAME, download.user.accountName) - added.putExtra(EXTRA_REMOTE_PATH, download.remotePath) - added.putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath) - added.setPackage(context.packageName) - localBroadcastManager.sendBroadcast(added) + val intent = Intent(getDownloadAddedMessage()).apply { + putExtra(ACCOUNT_NAME, download.user.accountName) + putExtra(EXTRA_REMOTE_PATH, download.remotePath) + putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath) + setPackage(context.packageName) + } + + localBroadcastManager.sendBroadcast(intent) } override fun onAccountsUpdated(accounts: Array?) { @@ -477,6 +492,7 @@ class FilesDownloadWorker( filePath: String ) { val percent: Int = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt() + if (percent != lastPercent) { notificationBuilder?.setProgress(100, percent, totalToTransfer < 0) val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) @@ -484,17 +500,22 @@ class FilesDownloadWorker( String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) notificationBuilder?.setContentText(text) - if (notificationManager == null) { - notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - } - notificationManager?.notify( - R.string.downloader_download_in_progress_ticker, - notificationBuilder?.build() - ) + notifyDownloadInProgressNotification() } + lastPercent = percent } + private fun notifyDownloadInProgressNotification() { + if (notificationManager == null) { + notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + } + notificationManager?.notify( + R.string.downloader_download_in_progress_ticker, + notificationBuilder?.build() + ) + } + inner class FileDownloaderBinder : Binder(), OnDatatransferProgressListener { private val boundListeners: MutableMap = HashMap() @@ -502,11 +523,13 @@ class FilesDownloadWorker( val removeResult: Pair = pendingDownloads.remove(account.name, file.remotePath) val download = removeResult.first + if (download != null) { download.cancel() } else { - if (currentDownload != null && currentUser?.isPresent == true && - currentDownload?.remotePath?.startsWith(file.remotePath) == true && account.name == currentUser.get()?.accountName + if (currentUser?.isPresent == true && + currentDownload?.remotePath?.startsWith(file.remotePath) == true && + account.name == currentUser.get()?.accountName ) { currentDownload?.cancel() } @@ -514,7 +537,7 @@ class FilesDownloadWorker( } fun cancelAllDownloadsForAccount(accountName: String?) { - if (currentDownload != null && currentDownload?.user?.nameEquals(accountName) == true) { + if (currentDownload?.user?.nameEquals(accountName) == true) { currentDownload?.cancel() } @@ -529,6 +552,7 @@ class FilesDownloadWorker( if (file == null || listener == null) { return } + boundListeners[file.fileId] = listener } @@ -536,6 +560,7 @@ class FilesDownloadWorker( if (file == null || listener == null) { return } + val fileId = file.fileId if (boundListeners[fileId] === listener) { boundListeners.remove(fileId) @@ -543,11 +568,13 @@ class FilesDownloadWorker( } override fun onTransferProgress( - progressRate: Long, totalTransferredSoFar: Long, - totalToTransfer: Long, fileName: String + progressRate: Long, + totalTransferredSoFar: Long, + totalToTransfer: Long, + fileName: String ) { - val boundListener = boundListeners[currentDownload?.file?.fileId] - boundListener?.onTransferProgress( + val listener = boundListeners[currentDownload?.file?.fileId] + listener?.onTransferProgress( progressRate, totalTransferredSoFar, totalToTransfer, fileName ) From 6fcc35f7de3c20596877042dafbdb738382c5dcb Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 20 Dec 2023 10:19:09 +0100 Subject: [PATCH 014/189] Code cleanup Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 266 ++++++++++-------- 1 file changed, 143 insertions(+), 123 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index fa0de11d9e74..bb46aa399ddc 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -112,8 +112,8 @@ class FilesDownloadWorker( private var currentDownload: DownloadFileOperation? = null private var conflictUploadId: Long? = null private var lastPercent = 0 - private var notificationBuilder: NotificationCompat.Builder? = null - private var notificationManager: NotificationManager? = null + private lateinit var notificationBuilder: NotificationCompat.Builder + private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager private val pendingDownloads = IndexedForest() private var downloadBinder: IBinder? = null private var currentUser = Optional.empty() @@ -126,15 +126,9 @@ class FilesDownloadWorker( return try { val requestDownloads = getRequestDownloads() - showDownloadingFilesNotification() + initNotificationBuilder() addAccountUpdateListener() - - val it: Iterator = requestDownloads.iterator() - while (it.hasNext()) { - val next = it.next() - Log_OC.e(TAG, "Download Key: $next") - downloadFile(next) - } + startDownloadForEachRequest(requestDownloads) Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() @@ -191,6 +185,35 @@ class FilesDownloadWorker( return requestedDownloads } + + private fun initNotificationBuilder() { + notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) + .setContentTitle(context.resources.getString(R.string.app_name)) + .setContentText(context.resources.getString(R.string.foreground_service_download)) + .setSmallIcon(R.drawable.notification_icon) + .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + } + + notification = notificationBuilder.build() + } + + private fun addAccountUpdateListener() { + val am = AccountManager.get(context) + am.addOnAccountsUpdatedListener(this, null, false) + } + + private fun startDownloadForEachRequest(requestDownloads: AbstractList) { + val it: Iterator = requestDownloads.iterator() + while (it.hasNext()) { + val next = it.next() + Log_OC.e(TAG, "Download Key: $next") + + downloadFile(next) + } + } private fun downloadFile(downloadKey: String) { startedDownload = true @@ -225,42 +248,31 @@ class FilesDownloadWorker( } } - private fun getOCAccountForDownload(): OwnCloudAccount { - val currentDownloadAccount = currentDownload?.user?.toPlatformAccount() - val currentDownloadUser = accountManager.getUser(currentDownloadAccount?.name) - if (currentUser != currentDownloadUser) { - currentUser = currentDownloadUser - storageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) - } - return currentDownloadUser.get().toOwnCloudAccount() + private fun cancelPendingDownloads(accountName: String?) { + pendingDownloads.remove(accountName) } - private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { - val removeResult = pendingDownloads.removePayload( - currentDownload?.user?.accountName, currentDownload?.remotePath - ) + private fun notifyDownloadStart(download: DownloadFileOperation) { + lastPercent = 0 - val downloadResult = result ?: RemoteOperationResult(RuntimeException("Error downloading…")) + configureNotificationBuilderForDownloadStart(download) - currentDownload?.run { - notifyDownloadResult(this, downloadResult) - sendBroadcastDownloadFinished(this, downloadResult, removeResult.second) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) } - } - - private fun getCurrentFile(): OCFile? { - var file: OCFile? = currentDownload?.file?.fileId?.let { storageManager?.getFileById(it) } - if (file == null) { - file = storageManager?.getFileByDecryptedRemotePath(currentDownload?.file?.remotePath) - } + showDetailsIntent(download) + notifyDownloadInProgressNotification() + } - if (file == null) { - Log_OC.e(this, "Could not save " + currentDownload?.file?.remotePath) - return null + private fun getOCAccountForDownload(): OwnCloudAccount { + val currentDownloadAccount = currentDownload?.user?.toPlatformAccount() + val currentDownloadUser = accountManager.getUser(currentDownloadAccount?.name) + if (currentUser != currentDownloadUser) { + currentUser = currentDownloadUser + storageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) } - - return file + return currentDownloadUser.get().toOwnCloudAccount() } private fun saveDownloadedFile() { @@ -295,60 +307,49 @@ class FilesDownloadWorker( storageManager?.saveConflict(file, null) } - private fun sendBroadcastDownloadFinished( - download: DownloadFileOperation, - downloadResult: RemoteOperationResult<*>, - unlinkedFromRemotePath: String? - ) { - val intent = Intent(getDownloadFinishMessage()).apply { - putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) - putExtra(ACCOUNT_NAME, download.user.accountName) - putExtra(EXTRA_REMOTE_PATH, download.remotePath) - putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) - putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) - putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) - if (unlinkedFromRemotePath != null) { - putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) - } - setPackage(context.packageName) + private fun getCurrentFile(): OCFile? { + var file: OCFile? = currentDownload?.file?.fileId?.let { storageManager?.getFileById(it) } + + if (file == null) { + file = storageManager?.getFileByDecryptedRemotePath(currentDownload?.file?.remotePath) } - localBroadcastManager.sendBroadcast(intent) + if (file == null) { + Log_OC.e(this, "Could not save " + currentDownload?.file?.remotePath) + return null + } + + return file + } + + private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { + val removeResult = pendingDownloads.removePayload( + currentDownload?.user?.accountName, currentDownload?.remotePath + ) + + val downloadResult = result ?: RemoteOperationResult(RuntimeException("Error downloading…")) + + currentDownload?.run { + notifyDownloadResult(this, downloadResult) + sendBroadcastDownloadFinished(this, downloadResult, removeResult.second) + } } private fun notifyDownloadResult( download: DownloadFileOperation, downloadResult: RemoteOperationResult<*> ) { - if (notificationManager == null) { - notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - } - if (downloadResult.isCancelled) { return } if (downloadResult.isSuccess) { - conflictUploadId?.let { - if (it > 0) { - uploadsStorageManager.removeUpload(it) - } - } - + dismissDownloadInProgressNotification() return } - var tickerId = - if (downloadResult.isSuccess) R.string.downloader_download_succeeded_ticker else R.string.downloader_download_failed_ticker val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) - tickerId = if (needsToUpdateCredentials) R.string.downloader_download_failed_credentials_error else tickerId - - notificationBuilder - ?.setTicker(context.getString(tickerId)) - ?.setContentTitle(context.getString(tickerId)) - ?.setAutoCancel(true) - ?.setOngoing(false) - ?.setProgress(0, 0, false) + configureNotificationBuilderForDownloadResult(downloadResult, needsToUpdateCredentials) if (needsToUpdateCredentials) { configureUpdateCredentialsNotification(download.user) @@ -356,23 +357,76 @@ class FilesDownloadWorker( showDetailsIntent(null) } - notificationBuilder?.setContentText( - ErrorMessageAdapter.getErrorCauseMessage( - downloadResult, - download, context.resources - ) + notifyNotificationBuilderForDownloadResult(downloadResult, download) + } + + private fun configureNotificationBuilderForDownloadResult( + downloadResult: RemoteOperationResult<*>, + needsToUpdateCredentials: Boolean + ) { + var tickerId = + if (downloadResult.isSuccess) R.string.downloader_download_succeeded_ticker else R.string.downloader_download_failed_ticker + tickerId = if (needsToUpdateCredentials) R.string.downloader_download_failed_credentials_error else tickerId + + notificationBuilder + .setTicker(context.getString(tickerId)) + .setContentTitle(context.getString(tickerId)) + .setAutoCancel(true) + .setOngoing(false) + .setProgress(0, 0, false) + } + + private fun notifyNotificationBuilderForDownloadResult(downloadResult: RemoteOperationResult<*>, download: DownloadFileOperation) { + val errorMessage = ErrorMessageAdapter.getErrorCauseMessage( + downloadResult, + download, + context.resources ) - notificationManager?.notify(SecureRandom().nextInt(), notificationBuilder?.build()) + notificationBuilder.setContentText(errorMessage) + + notificationManager.notify(SecureRandom().nextInt(), notificationBuilder.build()) if (downloadResult.isSuccess) { NotificationUtils.cancelWithDelay( notificationManager, - R.string.downloader_download_succeeded_ticker, 2000 + R.string.downloader_download_succeeded_ticker, + 2000 ) } } + private fun sendBroadcastDownloadFinished( + download: DownloadFileOperation, + downloadResult: RemoteOperationResult<*>, + unlinkedFromRemotePath: String? + ) { + val intent = Intent(getDownloadFinishMessage()).apply { + putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) + putExtra(ACCOUNT_NAME, download.user.accountName) + putExtra(EXTRA_REMOTE_PATH, download.remotePath) + putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) + putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) + putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) + if (unlinkedFromRemotePath != null) { + putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) + } + setPackage(context.packageName) + } + + localBroadcastManager.sendBroadcast(intent) + } + + private fun dismissDownloadInProgressNotification() { + conflictUploadId?.let { + if (it > 0) { + uploadsStorageManager.removeUpload(it) + } + } + + notificationManager.cancel(R.string.downloader_download_in_progress_ticker) + } + private fun configureUpdateCredentialsNotification(user: User) { val intent = Intent(context, AuthenticatorActivity::class.java).apply { putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) @@ -385,7 +439,7 @@ class FilesDownloadWorker( addFlags(Intent.FLAG_FROM_BACKGROUND) } - notificationBuilder?.setContentIntent( + notificationBuilder.setContentIntent( PendingIntent.getActivity( context, System.currentTimeMillis().toInt(), intent, @@ -394,8 +448,7 @@ class FilesDownloadWorker( ) } - private fun notifyDownloadStart(download: DownloadFileOperation) { - lastPercent = 0 + private fun configureNotificationBuilderForDownloadStart(download: DownloadFileOperation) { notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) .setSmallIcon(R.drawable.notification_icon) .setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) @@ -408,13 +461,6 @@ class FilesDownloadWorker( File(download.savePath).name ) ) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - notificationBuilder?.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) - } - - showDetailsIntent(download) - notifyDownloadInProgressNotification() } private fun showDetailsIntent(operation: DownloadFileOperation?) { @@ -432,7 +478,7 @@ class FilesDownloadWorker( Intent() } - notificationBuilder?.setContentIntent( + notificationBuilder.setContentIntent( PendingIntent.getActivity( context, System.currentTimeMillis().toInt(), @@ -442,29 +488,6 @@ class FilesDownloadWorker( ) } - private fun showDownloadingFilesNotification() { - val builder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) - .setContentTitle(context.resources.getString(R.string.app_name)) - .setContentText(context.resources.getString(R.string.foreground_service_download)) - .setSmallIcon(R.drawable.notification_icon) - .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - builder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) - } - - notification = builder.build() - } - - private fun addAccountUpdateListener() { - val am = AccountManager.get(context) - am.addOnAccountsUpdatedListener(this, null, false) - } - - private fun cancelPendingDownloads(accountName: String?) { - pendingDownloads.remove(accountName) - } - private fun sendBroadcastNewDownload( download: DownloadFileOperation, linkedToRemotePath: String @@ -494,11 +517,11 @@ class FilesDownloadWorker( val percent: Int = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt() if (percent != lastPercent) { - notificationBuilder?.setProgress(100, percent, totalToTransfer < 0) + notificationBuilder.setProgress(100, percent, totalToTransfer < 0) val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) val text = String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) - notificationBuilder?.setContentText(text) + notificationBuilder.setContentText(text) notifyDownloadInProgressNotification() } @@ -507,12 +530,9 @@ class FilesDownloadWorker( } private fun notifyDownloadInProgressNotification() { - if (notificationManager == null) { - notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - } - notificationManager?.notify( + notificationManager.notify( R.string.downloader_download_in_progress_ticker, - notificationBuilder?.build() + notificationBuilder.build() ) } From 842ff87c848f55de184be16b5aab312d77631e91 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 20 Dec 2023 11:33:29 +0100 Subject: [PATCH 015/189] Fix download progress Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadHelper.kt | 6 +++--- .../files/downloader/FilesDownloadWorker.kt | 18 ++++++++++++------ .../android/ui/activity/ComponentsGetter.java | 2 +- .../ui/activity/FileDisplayActivity.java | 3 ++- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt index 8a0a855f84b5..94803b9b297c 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt @@ -46,7 +46,7 @@ class FilesDownloadHelper { user, ocFile, "", - null, + DownloadType.DOWNLOAD, "", "", null @@ -58,7 +58,7 @@ class FilesDownloadHelper { user, ocFile, behaviour, - null, + DownloadType.DOWNLOAD, "", "", null @@ -82,7 +82,7 @@ class FilesDownloadHelper { user, ocFile, "", - null, + DownloadType.DOWNLOAD, "", "", conflictUploadId diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index bb46aa399ddc..b9bd074c64ef 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -115,7 +115,7 @@ class FilesDownloadWorker( private lateinit var notificationBuilder: NotificationCompat.Builder private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager private val pendingDownloads = IndexedForest() - private var downloadBinder: IBinder? = null + private var downloadBinder: IBinder = FileDownloaderBinder() private var currentUser = Optional.empty() private var startedDownload = false private var storageManager: FileDataStorageManager? = null @@ -158,6 +158,7 @@ class FilesDownloadWorker( val packageName = inputData.keyValueMap[PACKAGE_NAME] as String val requestedDownloads: AbstractList = Vector() + try { val operation = DownloadFileOperation( user, @@ -169,16 +170,19 @@ class FilesDownloadWorker( downloadType ) operation.addDatatransferProgressListener(this) - operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder?) + operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder) val putResult = pendingDownloads.putIfAbsent( user?.accountName, file.remotePath, operation ) - val downloadKey = putResult.first - requestedDownloads.add(downloadKey) - sendBroadcastNewDownload(operation, putResult.second) + if (putResult != null) { + val downloadKey = putResult.first + requestedDownloads.add(downloadKey) + sendBroadcastNewDownload(operation, putResult.second) + } + } catch (e: IllegalArgumentException) { Log_OC.e(TAG, "Not enough information provided in intent: " + e.message) } @@ -207,12 +211,14 @@ class FilesDownloadWorker( private fun startDownloadForEachRequest(requestDownloads: AbstractList) { val it: Iterator = requestDownloads.iterator() + while (it.hasNext()) { val next = it.next() Log_OC.e(TAG, "Download Key: $next") - downloadFile(next) } + + startedDownload = false } private fun downloadFile(downloadKey: String) { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java index 4b0ab8c6de2e..9ae88f3c7248 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java @@ -30,7 +30,7 @@ public interface ComponentsGetter { /** * To be invoked when the parent activity is fully created to get a reference - * to the FileDownloader service API. + * to the FileDownloadWorker. */ public FilesDownloadWorker.FileDownloaderBinder getFileDownloaderBinder(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 106dac2e027e..7e110b45a2c9 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -94,6 +94,7 @@ import com.owncloud.android.lib.resources.files.SearchRemoteOperation; import com.owncloud.android.operations.CopyFileOperation; import com.owncloud.android.operations.CreateFolderOperation; +import com.owncloud.android.operations.DownloadType; import com.owncloud.android.operations.MoveFileOperation; import com.owncloud.android.operations.RefreshFolderOperation; import com.owncloud.android.operations.RemoveFileOperation; @@ -1957,7 +1958,7 @@ public void run() { private void requestForDownload(OCFile file, String downloadBehaviour, String packageName, String activityName) { final User currentUser = getUser().orElseThrow(RuntimeException::new); if (!mDownloaderBinder.isDownloading(currentUser, mWaitingToPreview)) { - new FilesDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, null, activityName, packageName, null); + new FilesDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); } } From cf09356cf7dfa46c9e24750017632187b1a14c7d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 20 Dec 2023 12:46:36 +0100 Subject: [PATCH 016/189] Cleanup code Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadHelper.kt | 39 +++ .../files/downloader/FilesDownloadIntents.kt | 83 ++++++ .../files/downloader/FilesDownloadWorker.kt | 273 +++--------------- .../client/jobs/BackgroundJobManager.kt | 1 + .../client/jobs/BackgroundJobManagerImpl.kt | 2 +- .../download/DownloadNotificationManager.kt | 175 +++++++++++ 6 files changed, 335 insertions(+), 238 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt create mode 100644 app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt index 94803b9b297c..328d4b4b164d 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt @@ -24,9 +24,13 @@ package com.nextcloud.client.files.downloader import com.nextcloud.client.account.User import com.nextcloud.client.jobs.BackgroundJobManager import com.owncloud.android.MainApp +import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager +import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType +import com.owncloud.android.utils.MimeTypeUtil +import java.io.File import javax.inject.Inject class FilesDownloadHelper { @@ -41,6 +45,40 @@ class FilesDownloadHelper { MainApp.getAppComponent().inject(this) } + fun saveFile( + file: OCFile, + currentDownload: DownloadFileOperation?, + storageManager: FileDataStorageManager? + ) { + val syncDate = System.currentTimeMillis() + + file.apply { + lastSyncDateForProperties = syncDate + lastSyncDateForData = syncDate + isUpdateThumbnailNeeded = true + modificationTimestamp = currentDownload?.modificationTimestamp ?: 0L + modificationTimestampAtLastSyncForData = currentDownload?.modificationTimestamp ?: 0L + etag = currentDownload?.etag + mimeType = currentDownload?.mimeType + storagePath = currentDownload?.savePath + + val savePathFile = currentDownload?.savePath?.let { File(it) } + savePathFile?.let { + fileLength = savePathFile.length() + } + + remoteId = currentDownload?.file?.remoteId + } + + storageManager?.saveFile(file) + + if (MimeTypeUtil.isMedia(currentDownload?.mimeType)) { + FileDataStorageManager.triggerMediaScan(file.storagePath, file) + } + + storageManager?.saveConflict(file, null) + } + fun downloadFile(user: User, ocFile: OCFile) { backgroundJobManager.startFilesDownloadJob( user, @@ -89,6 +127,7 @@ class FilesDownloadHelper { ) } + @Suppress("LongParameterList") fun downloadFile( user: User, ocFile: OCFile, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt new file mode 100644 index 000000000000..d8d6e67a2c8f --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt @@ -0,0 +1,83 @@ +/* + * 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 . + */ + +package com.nextcloud.client.files.downloader + +import android.content.Context +import android.content.Intent +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.operations.DownloadFileOperation +import com.owncloud.android.ui.activity.FileActivity +import com.owncloud.android.ui.activity.FileDisplayActivity +import com.owncloud.android.ui.dialog.SendShareDialog +import com.owncloud.android.ui.fragment.OCFileListFragment +import com.owncloud.android.ui.preview.PreviewImageActivity +import com.owncloud.android.ui.preview.PreviewImageFragment + +class FilesDownloadIntents(private val context: Context) { + + fun newDownloadIntent( + download: DownloadFileOperation, + linkedToRemotePath: String + ): Intent { + return Intent(FilesDownloadWorker.getDownloadAddedMessage()).apply { + putExtra(FilesDownloadWorker.ACCOUNT_NAME, download.user.accountName) + putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) + putExtra(FilesDownloadWorker.EXTRA_LINKED_TO_PATH, linkedToRemotePath) + setPackage(context.packageName) + } + } + + fun downloadFinishedIntent( + download: DownloadFileOperation, + downloadResult: RemoteOperationResult<*>, + unlinkedFromRemotePath: String? + ): Intent { + return Intent(FilesDownloadWorker.getDownloadFinishMessage()).apply { + putExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) + putExtra(FilesDownloadWorker.ACCOUNT_NAME, download.user.accountName) + putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) + putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) + putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) + putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) + if (unlinkedFromRemotePath != null) { + putExtra(FilesDownloadWorker.EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) + } + setPackage(context.packageName) + } + } + + fun detailsIntent(operation: DownloadFileOperation?): Intent { + return if (operation != null) { + if (PreviewImageFragment.canBePreviewed(operation.file)) { + Intent(context, PreviewImageActivity::class.java) + } else { + Intent(context, FileDisplayActivity::class.java) + }.apply { + putExtra(FileActivity.EXTRA_FILE, operation.file) + putExtra(FileActivity.EXTRA_USER, operation.user) + flags = Intent.FLAG_ACTIVITY_CLEAR_TOP + } + } else { + Intent() + } + } +} diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index b9bd074c64ef..79bd327cc50a 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -24,26 +24,19 @@ package com.nextcloud.client.files.downloader import android.accounts.Account import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener -import android.app.Notification -import android.app.NotificationManager import android.app.PendingIntent import android.content.Context -import android.content.Intent -import android.graphics.BitmapFactory import android.os.Binder -import android.os.Build import android.os.IBinder import android.util.Pair -import androidx.core.app.NotificationCompat import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters import com.google.gson.Gson import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional -import com.owncloud.android.R -import com.owncloud.android.authentication.AuthenticatorActivity import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager @@ -55,31 +48,20 @@ import com.owncloud.android.lib.common.network.OnDatatransferProgressListener import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode import com.owncloud.android.lib.common.utils.Log_OC -import com.owncloud.android.lib.resources.files.FileUtils import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType -import com.owncloud.android.ui.activity.FileActivity -import com.owncloud.android.ui.activity.FileDisplayActivity -import com.owncloud.android.ui.dialog.SendShareDialog -import com.owncloud.android.ui.fragment.OCFileListFragment -import com.owncloud.android.ui.notifications.NotificationUtils -import com.owncloud.android.ui.preview.PreviewImageActivity -import com.owncloud.android.ui.preview.PreviewImageFragment -import com.owncloud.android.utils.ErrorMessageAdapter -import com.owncloud.android.utils.MimeTypeUtil import com.owncloud.android.utils.theme.ViewThemeUtils -import java.io.File -import java.security.SecureRandom import java.util.AbstractList import java.util.Vector +@Suppress("LongParameterList") class FilesDownloadWorker( private val viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, private val uploadsStorageManager: UploadsStorageManager, private var localBroadcastManager: LocalBroadcastManager, private val context: Context, - params: WorkerParameters, + params: WorkerParameters ) : Worker(context, params), OnAccountsUpdateListener, OnDatatransferProgressListener { companion object { @@ -108,25 +90,26 @@ class FilesDownloadWorker( } } - private var notification: Notification? = null private var currentDownload: DownloadFileOperation? = null private var conflictUploadId: Long? = null private var lastPercent = 0 - private lateinit var notificationBuilder: NotificationCompat.Builder - private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + private val intents = FilesDownloadIntents(context) + private val notificationManager = DownloadNotificationManager(context, viewThemeUtils) private val pendingDownloads = IndexedForest() private var downloadBinder: IBinder = FileDownloaderBinder() private var currentUser = Optional.empty() + private val helper = FilesDownloadHelper() private var startedDownload = false private var storageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null private val gson = Gson() + @Suppress("TooGenericExceptionCaught") override fun doWork(): Result { return try { val requestDownloads = getRequestDownloads() - initNotificationBuilder() + notificationManager.init() addAccountUpdateListener() startDownloadForEachRequest(requestDownloads) @@ -180,29 +163,14 @@ class FilesDownloadWorker( if (putResult != null) { val downloadKey = putResult.first requestedDownloads.add(downloadKey) - sendBroadcastNewDownload(operation, putResult.second) + localBroadcastManager.sendBroadcast(intents.newDownloadIntent(operation, putResult.second)) } - } catch (e: IllegalArgumentException) { Log_OC.e(TAG, "Not enough information provided in intent: " + e.message) } return requestedDownloads } - - private fun initNotificationBuilder() { - notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) - .setContentTitle(context.resources.getString(R.string.app_name)) - .setContentText(context.resources.getString(R.string.foreground_service_download)) - .setSmallIcon(R.drawable.notification_icon) - .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) - } - - notification = notificationBuilder.build() - } private fun addAccountUpdateListener() { val am = AccountManager.get(context) @@ -221,6 +189,7 @@ class FilesDownloadWorker( startedDownload = false } + @Suppress("TooGenericExceptionCaught") private fun downloadFile(downloadKey: String) { startedDownload = true currentDownload = pendingDownloads.get(downloadKey) @@ -244,7 +213,9 @@ class FilesDownloadWorker( downloadResult = currentDownload?.execute(downloadClient) if (downloadResult?.isSuccess == true && currentDownload?.downloadType === DownloadType.DOWNLOAD) { - saveDownloadedFile() + getCurrentFile()?.let { + helper.saveFile(it, currentDownload, storageManager) + } } } catch (e: Exception) { Log_OC.e(TAG, "Error downloading", e) @@ -261,14 +232,9 @@ class FilesDownloadWorker( private fun notifyDownloadStart(download: DownloadFileOperation) { lastPercent = 0 - configureNotificationBuilderForDownloadStart(download) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) - } - - showDetailsIntent(download) - notifyDownloadInProgressNotification() + notificationManager.notifyForStart(download) + notificationManager.setContentIntent(intents.detailsIntent(download), PendingIntent.FLAG_IMMUTABLE) + notificationManager.showDownloadInProgressNotification() } private fun getOCAccountForDownload(): OwnCloudAccount { @@ -281,38 +247,6 @@ class FilesDownloadWorker( return currentDownloadUser.get().toOwnCloudAccount() } - private fun saveDownloadedFile() { - val file = getCurrentFile() ?: return - - val syncDate = System.currentTimeMillis() - - file.apply { - lastSyncDateForProperties = syncDate - lastSyncDateForData = syncDate - isUpdateThumbnailNeeded = true - modificationTimestamp = currentDownload?.modificationTimestamp ?: 0L - modificationTimestampAtLastSyncForData = currentDownload?.modificationTimestamp ?: 0L - etag = currentDownload?.etag - mimeType = currentDownload?.mimeType - storagePath = currentDownload?.savePath - - val savePathFile = currentDownload?.savePath?.let { File(it) } - savePathFile?.let { - fileLength = savePathFile.length() - } - - remoteId = currentDownload?.file?.remoteId - } - - storageManager?.saveFile(file) - - if (MimeTypeUtil.isMedia(currentDownload?.mimeType)) { - FileDataStorageManager.triggerMediaScan(file.storagePath, file) - } - - storageManager?.saveConflict(file, null) - } - private fun getCurrentFile(): OCFile? { var file: OCFile? = currentDownload?.file?.fileId?.let { storageManager?.getFileById(it) } @@ -330,14 +264,20 @@ class FilesDownloadWorker( private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { val removeResult = pendingDownloads.removePayload( - currentDownload?.user?.accountName, currentDownload?.remotePath + currentDownload?.user?.accountName, + currentDownload?.remotePath ) val downloadResult = result ?: RemoteOperationResult(RuntimeException("Error downloading…")) currentDownload?.run { notifyDownloadResult(this, downloadResult) - sendBroadcastDownloadFinished(this, downloadResult, removeResult.second) + val downloadFinishedIntent = intents.downloadFinishedIntent( + this, + downloadResult, + removeResult.second + ) + localBroadcastManager.sendBroadcast(downloadFinishedIntent) } } @@ -355,72 +295,15 @@ class FilesDownloadWorker( } val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) - configureNotificationBuilderForDownloadResult(downloadResult, needsToUpdateCredentials) + notificationManager.prepareForResult(downloadResult, needsToUpdateCredentials) if (needsToUpdateCredentials) { - configureUpdateCredentialsNotification(download.user) + notificationManager.setCredentialContentIntent(download.user) } else { - showDetailsIntent(null) - } - - notifyNotificationBuilderForDownloadResult(downloadResult, download) - } - - private fun configureNotificationBuilderForDownloadResult( - downloadResult: RemoteOperationResult<*>, - needsToUpdateCredentials: Boolean - ) { - var tickerId = - if (downloadResult.isSuccess) R.string.downloader_download_succeeded_ticker else R.string.downloader_download_failed_ticker - tickerId = if (needsToUpdateCredentials) R.string.downloader_download_failed_credentials_error else tickerId - - notificationBuilder - .setTicker(context.getString(tickerId)) - .setContentTitle(context.getString(tickerId)) - .setAutoCancel(true) - .setOngoing(false) - .setProgress(0, 0, false) - } - - private fun notifyNotificationBuilderForDownloadResult(downloadResult: RemoteOperationResult<*>, download: DownloadFileOperation) { - val errorMessage = ErrorMessageAdapter.getErrorCauseMessage( - downloadResult, - download, - context.resources - ) - - notificationBuilder.setContentText(errorMessage) - - notificationManager.notify(SecureRandom().nextInt(), notificationBuilder.build()) - - if (downloadResult.isSuccess) { - NotificationUtils.cancelWithDelay( - notificationManager, - R.string.downloader_download_succeeded_ticker, - 2000 - ) - } - } - - private fun sendBroadcastDownloadFinished( - download: DownloadFileOperation, - downloadResult: RemoteOperationResult<*>, - unlinkedFromRemotePath: String? - ) { - val intent = Intent(getDownloadFinishMessage()).apply { - putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) - putExtra(ACCOUNT_NAME, download.user.accountName) - putExtra(EXTRA_REMOTE_PATH, download.remotePath) - putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) - putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) - putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) - if (unlinkedFromRemotePath != null) { - putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) - } - setPackage(context.packageName) + notificationManager.setContentIntent(intents.detailsIntent(null), PendingIntent.FLAG_IMMUTABLE) } - localBroadcastManager.sendBroadcast(intent) + notificationManager.notifyForResult(downloadResult, download) } private fun dismissDownloadInProgressNotification() { @@ -430,82 +313,7 @@ class FilesDownloadWorker( } } - notificationManager.cancel(R.string.downloader_download_in_progress_ticker) - } - - private fun configureUpdateCredentialsNotification(user: User) { - val intent = Intent(context, AuthenticatorActivity::class.java).apply { - putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) - putExtra( - AuthenticatorActivity.EXTRA_ACTION, - AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN - ) - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) - addFlags(Intent.FLAG_FROM_BACKGROUND) - } - - notificationBuilder.setContentIntent( - PendingIntent.getActivity( - context, System.currentTimeMillis().toInt(), - intent, - PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE - ) - ) - } - - private fun configureNotificationBuilderForDownloadStart(download: DownloadFileOperation) { - notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) - .setSmallIcon(R.drawable.notification_icon) - .setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) - .setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) - .setOngoing(true) - .setProgress(100, 0, download.size < 0) - .setContentText( - String.format( - context.getString(R.string.downloader_download_in_progress_content), 0, - File(download.savePath).name - ) - ) - } - - private fun showDetailsIntent(operation: DownloadFileOperation?) { - val intent: Intent = if (operation != null) { - if (PreviewImageFragment.canBePreviewed(operation.file)) { - Intent(context, PreviewImageActivity::class.java) - } else { - Intent(context, FileDisplayActivity::class.java) - }.apply { - putExtra(FileActivity.EXTRA_FILE, operation.file) - putExtra(FileActivity.EXTRA_USER, operation.user) - flags = Intent.FLAG_ACTIVITY_CLEAR_TOP - } - } else { - Intent() - } - - notificationBuilder.setContentIntent( - PendingIntent.getActivity( - context, - System.currentTimeMillis().toInt(), - intent, - PendingIntent.FLAG_IMMUTABLE - ) - ) - } - - private fun sendBroadcastNewDownload( - download: DownloadFileOperation, - linkedToRemotePath: String - ) { - val intent = Intent(getDownloadAddedMessage()).apply { - putExtra(ACCOUNT_NAME, download.user.accountName) - putExtra(EXTRA_REMOTE_PATH, download.remotePath) - putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath) - setPackage(context.packageName) - } - - localBroadcastManager.sendBroadcast(intent) + notificationManager.dismissDownloadInProgressNotification() } override fun onAccountsUpdated(accounts: Array?) { @@ -514,6 +322,7 @@ class FilesDownloadWorker( } } + @Suppress("MagicNumber") override fun onTransferProgress( progressRate: Long, totalTransferredSoFar: Long, @@ -523,25 +332,13 @@ class FilesDownloadWorker( val percent: Int = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt() if (percent != lastPercent) { - notificationBuilder.setProgress(100, percent, totalToTransfer < 0) - val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) - val text = - String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) - notificationBuilder.setContentText(text) - - notifyDownloadInProgressNotification() + notificationManager.updateDownloadProgressNotification(filePath, percent, totalToTransfer) + notificationManager.showDownloadInProgressNotification() } lastPercent = percent } - private fun notifyDownloadInProgressNotification() { - notificationManager.notify( - R.string.downloader_download_in_progress_ticker, - notificationBuilder.build() - ) - } - inner class FileDownloaderBinder : Binder(), OnDatatransferProgressListener { private val boundListeners: MutableMap = HashMap() @@ -601,8 +398,10 @@ class FilesDownloadWorker( ) { val listener = boundListeners[currentDownload?.file?.fileId] listener?.onTransferProgress( - progressRate, totalTransferredSoFar, - totalToTransfer, fileName + progressRate, + totalTransferredSoFar, + totalToTransfer, + fileName ) } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 30f7ab3c7595..30b90d1fbe18 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -145,6 +145,7 @@ interface BackgroundJobManager { fun getFileUploads(user: User): LiveData> fun cancelFilesUploadJob(user: User) + @Suppress("LongParameterList") fun startFilesDownloadJob( user: User, ocFile: OCFile, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index bad195010b08..f31f41722311 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -527,7 +527,7 @@ internal class BackgroundJobManagerImpl( FilesDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), FilesDownloadWorker.ACTIVITY_NAME to activityName, FilesDownloadWorker.PACKAGE_NAME to packageName, - FilesDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId, + FilesDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId ) val request = oneTimeRequestBuilder(FilesDownloadWorker::class, JOB_FILES_DOWNLOAD, user) diff --git a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt new file mode 100644 index 000000000000..0bd056e19cbb --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt @@ -0,0 +1,175 @@ +/* + * 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 . + */ + +package com.nextcloud.client.notifications.download + +import android.app.Notification +import android.app.NotificationManager +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.graphics.BitmapFactory +import android.os.Build +import androidx.core.app.NotificationCompat +import com.nextcloud.client.account.User +import com.owncloud.android.R +import com.owncloud.android.authentication.AuthenticatorActivity +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.resources.files.FileUtils +import com.owncloud.android.operations.DownloadFileOperation +import com.owncloud.android.ui.notifications.NotificationUtils +import com.owncloud.android.utils.ErrorMessageAdapter +import com.owncloud.android.utils.theme.ViewThemeUtils +import java.io.File +import java.security.SecureRandom + +class DownloadNotificationManager(private val context: Context, private val viewThemeUtils: ViewThemeUtils) { + + private var notification: Notification? = null + private lateinit var notificationBuilder: NotificationCompat.Builder + private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + + fun init() { + notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) + .setContentTitle(context.resources.getString(R.string.app_name)) + .setContentText(context.resources.getString(R.string.foreground_service_download)) + .setSmallIcon(R.drawable.notification_icon) + .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + } + + notification = notificationBuilder.build() + } + + @Suppress("MagicNumber") + fun notifyForStart(operation: DownloadFileOperation) { + notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) + .setSmallIcon(R.drawable.notification_icon) + .setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) + .setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) + .setOngoing(true) + .setProgress(100, 0, operation.size < 0) + .setContentText( + String.format( + context.getString(R.string.downloader_download_in_progress_content), 0, + File(operation.savePath).name + ) + ) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + } + } + + @Suppress("MagicNumber") + fun notifyForResult(result: RemoteOperationResult<*>, download: DownloadFileOperation) { + val errorMessage = ErrorMessageAdapter.getErrorCauseMessage( + result, + download, + context.resources + ) + + notificationBuilder.setContentText(errorMessage) + + notificationManager.notify(SecureRandom().nextInt(), notificationBuilder.build()) + + if (result.isSuccess) { + NotificationUtils.cancelWithDelay( + notificationManager, + R.string.downloader_download_succeeded_ticker, + 2000 + ) + } + } + + fun prepareForResult( + downloadResult: RemoteOperationResult<*>, + needsToUpdateCredentials: Boolean + ) { + var tickerId = + if (downloadResult.isSuccess) { + R.string.downloader_download_succeeded_ticker + } else { + R.string.downloader_download_failed_ticker + } + + tickerId = if (needsToUpdateCredentials) { + R.string.downloader_download_failed_credentials_error + } else { + tickerId + } + + notificationBuilder + .setTicker(context.getString(tickerId)) + .setContentTitle(context.getString(tickerId)) + .setAutoCancel(true) + .setOngoing(false) + .setProgress(0, 0, false) + } + + @Suppress("MagicNumber") + fun updateDownloadProgressNotification(filePath: String, percent: Int, totalToTransfer: Long) { + notificationBuilder.setProgress(100, percent, totalToTransfer < 0) + val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) + val text = + String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) + notificationBuilder.setContentText(text) + } + + fun showDownloadInProgressNotification() { + notificationManager.notify( + R.string.downloader_download_in_progress_ticker, + notificationBuilder.build() + ) + } + + fun dismissDownloadInProgressNotification() { + notificationManager.cancel(R.string.downloader_download_in_progress_ticker) + } + + fun setCredentialContentIntent(user: User) { + val intent = Intent(context, AuthenticatorActivity::class.java).apply { + putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) + putExtra( + AuthenticatorActivity.EXTRA_ACTION, + AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN + ) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + addFlags(Intent.FLAG_FROM_BACKGROUND) + } + + setContentIntent(intent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE) + } + + fun setContentIntent(intent: Intent, flag: Int) { + notificationBuilder.setContentIntent( + PendingIntent.getActivity( + context, + System.currentTimeMillis().toInt(), + intent, + flag + ) + ) + } +} From 8308f187faaebc2c3f6ba7cc11f883e7868cfcf8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Dec 2023 14:15:30 +0100 Subject: [PATCH 017/189] Solve git conflicts Signed-off-by: alperozturk --- .../nextcloud/client/files/downloader/FilesDownloadIntents.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt index d8d6e67a2c8f..4c5a5b2c780c 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt @@ -80,4 +80,5 @@ class FilesDownloadIntents(private val context: Context) { Intent() } } + } From e2b75915e74a9a88bfd50cce18b8a8a6b8d7bcd2 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 09:17:16 +0100 Subject: [PATCH 018/189] Create download worker Signed-off-by: alperozturk --- .../client/files/downloader/DownloadWorker.kt | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt new file mode 100644 index 000000000000..70cfe01e674a --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt @@ -0,0 +1,39 @@ +/* + * 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 . + */ + +package com.nextcloud.client.files.downloader + +import android.content.Context +import android.content.Intent +import androidx.work.Worker +import androidx.work.WorkerParameters +import com.owncloud.android.files.services.FileDownloader + +class DownloadWorker( + private val context: Context, + params: WorkerParameters, + private val intent: Intent, + private val fileDownloader: FileDownloader, +) : Worker(context, params) { + override fun doWork(): Result { + TODO("Not yet implemented") + } +} From 7588dc543069e25121f6f98a93cc5980ad6aa57b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 10:44:55 +0100 Subject: [PATCH 019/189] Implement files download worker constructor Signed-off-by: alperozturk --- .../client/files/downloader/DownloadWorker.kt | 39 ------------------- .../client/jobs/BackgroundJobFactory.kt | 11 ++++++ 2 files changed, 11 insertions(+), 39 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt deleted file mode 100644 index 70cfe01e674a..000000000000 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt +++ /dev/null @@ -1,39 +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 . - */ - -package com.nextcloud.client.files.downloader - -import android.content.Context -import android.content.Intent -import androidx.work.Worker -import androidx.work.WorkerParameters -import com.owncloud.android.files.services.FileDownloader - -class DownloadWorker( - private val context: Context, - params: WorkerParameters, - private val intent: Intent, - private val fileDownloader: FileDownloader, -) : Worker(context, params) { - override fun doWork(): Result { - TODO("Not yet implemented") - } -} diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt index 38debc763eed..9526f41150fe 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt @@ -266,6 +266,17 @@ class BackgroundJobFactory @Inject constructor( ) } + private fun createFilesDownloadWorker(context: Context, params: WorkerParameters): FilesDownloadWorker { + return FilesDownloadWorker( + viewThemeUtils.get(), + accountManager, + uploadsStorageManager, + localBroadcastManager.get(), + context, + params + ) + } + private fun createPDFGenerateWork(context: Context, params: WorkerParameters): GeneratePdfFromImagesWork { return GeneratePdfFromImagesWork( appContext = context, From daa882aa200a0e1d8ec72c846f4ad767c3c3bbfe Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 16:28:37 +0100 Subject: [PATCH 020/189] Use interfaceSerializer Signed-off-by: alperozturk --- .../nextcloud/utils/InterfaceSerializer.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java diff --git a/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java b/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java new file mode 100644 index 000000000000..da253c14d9b5 --- /dev/null +++ b/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java @@ -0,0 +1,56 @@ +/* + * 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 . + */ + +package com.nextcloud.utils; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +import java.lang.reflect.Type; + +final public class InterfaceSerializer implements JsonSerializer, JsonDeserializer { + + private final Class implementationClass; + + private InterfaceSerializer(final Class implementationClass) { + this.implementationClass = implementationClass; + } + + public static InterfaceSerializer interfaceSerializer(final Class implementationClass) { + return new InterfaceSerializer<>(implementationClass); + } + + @Override + public JsonElement serialize(final T value, final Type type, final JsonSerializationContext context) { + final Type targetType = value != null + ? value.getClass() + : type; + return context.serialize(value, targetType); + } + + @Override + public T deserialize(final JsonElement jsonElement, final Type typeOfT, final JsonDeserializationContext context) { + return context.deserialize(jsonElement, implementationClass); + } +} From e1238e3bd1efb88c4e0977481801027b5cd5f4a8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 20 Dec 2023 09:13:15 +0100 Subject: [PATCH 021/189] Create user from accountName Signed-off-by: alperozturk --- .../nextcloud/utils/InterfaceSerializer.java | 56 ------------------- 1 file changed, 56 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java diff --git a/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java b/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java deleted file mode 100644 index da253c14d9b5..000000000000 --- a/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java +++ /dev/null @@ -1,56 +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 . - */ - -package com.nextcloud.utils; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; - -import java.lang.reflect.Type; - -final public class InterfaceSerializer implements JsonSerializer, JsonDeserializer { - - private final Class implementationClass; - - private InterfaceSerializer(final Class implementationClass) { - this.implementationClass = implementationClass; - } - - public static InterfaceSerializer interfaceSerializer(final Class implementationClass) { - return new InterfaceSerializer<>(implementationClass); - } - - @Override - public JsonElement serialize(final T value, final Type type, final JsonSerializationContext context) { - final Type targetType = value != null - ? value.getClass() - : type; - return context.serialize(value, targetType); - } - - @Override - public T deserialize(final JsonElement jsonElement, final Type typeOfT, final JsonDeserializationContext context) { - return context.deserialize(jsonElement, implementationClass); - } -} From e123128d90d238910f00dd2dd4a87667ec82cb44 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Dec 2023 14:50:00 +0100 Subject: [PATCH 022/189] Solve git conflicts Signed-off-by: alperozturk --- .../client/files/downloader/FilesDownloadIntents.kt | 1 - .../com/nextcloud/client/jobs/BackgroundJobFactory.kt | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt index 4c5a5b2c780c..d8d6e67a2c8f 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt @@ -80,5 +80,4 @@ class FilesDownloadIntents(private val context: Context) { Intent() } } - } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt index 9526f41150fe..38debc763eed 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt @@ -266,17 +266,6 @@ class BackgroundJobFactory @Inject constructor( ) } - private fun createFilesDownloadWorker(context: Context, params: WorkerParameters): FilesDownloadWorker { - return FilesDownloadWorker( - viewThemeUtils.get(), - accountManager, - uploadsStorageManager, - localBroadcastManager.get(), - context, - params - ) - } - private fun createPDFGenerateWork(context: Context, params: WorkerParameters): GeneratePdfFromImagesWork { return GeneratePdfFromImagesWork( appContext = context, From 414e6a668a20f592c110226f399ebec1f29a6d1c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Dec 2023 15:53:07 +0100 Subject: [PATCH 023/189] Remove Download Service Connections Signed-off-by: alperozturk --- .../com/owncloud/android/ui/activity/FileActivity.java | 9 ++------- .../android/ui/activity/ManageAccountsActivity.java | 10 ---------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index 2a89b567e764..e36c0e9ed2ca 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -168,7 +168,6 @@ public abstract class FileActivity extends DrawerActivity protected FilesDownloadWorker.FileDownloaderBinder mDownloaderBinder; protected FileUploaderBinder mUploaderBinder; - private ServiceConnection mDownloadServiceConnection; private ServiceConnection mUploadServiceConnection; @Inject @@ -234,10 +233,10 @@ protected void onCreate(Bundle savedInstanceState) { bindService(new Intent(this, OperationsService.class), mOperationsServiceConnection, Context.BIND_AUTO_CREATE); - mDownloadServiceConnection = newTransferenceServiceConnection(); - if (mDownloadServiceConnection != null && user != null) { + if (user != null) { new FilesDownloadHelper().downloadFile(user, mFile); } + mUploadServiceConnection = newTransferenceServiceConnection(); if (mUploadServiceConnection != null) { bindService(new Intent(this, FileUploader.class), mUploadServiceConnection, @@ -281,10 +280,6 @@ protected void onDestroy() { unbindService(mOperationsServiceConnection); mOperationsServiceBinder = null; } - if (mDownloadServiceConnection != null) { - unbindService(mDownloadServiceConnection); - mDownloadServiceConnection = null; - } if (mUploadServiceConnection != null) { unbindService(mUploadServiceConnection); mUploadServiceConnection = null; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 1cd495dfee49..24622e11414a 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -105,7 +105,6 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap private final Handler handler = new Handler(); private String accountName; private UserListAdapter userListAdapter; - private ServiceConnection downloadServiceConnection; private ServiceConnection uploadServiceConnection; private Set originalUsers; private String originalCurrentUser; @@ -241,11 +240,6 @@ private boolean hasCurrentAccountChanged() { * Initialize ComponentsGetters. */ private void initializeComponentGetters() { - downloadServiceConnection = newTransferenceServiceConnection(); - if (downloadServiceConnection != null) { - // FIXME check this usage - // bindService(new Intent(this, FileDownloader.class), downloadServiceConnection, Context.BIND_AUTO_CREATE); - } uploadServiceConnection = newTransferenceServiceConnection(); if (uploadServiceConnection != null) { bindService(new Intent(this, FileUploader.class), uploadServiceConnection, @@ -374,10 +368,6 @@ public void run(AccountManagerFuture future) { @Override protected void onDestroy() { - if (downloadServiceConnection != null) { - unbindService(downloadServiceConnection); - downloadServiceConnection = null; - } if (uploadServiceConnection != null) { unbindService(uploadServiceConnection); uploadServiceConnection = null; From 6bd335cf3c39e850146b0fbdd9ac37b869a26794 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 26 Dec 2023 10:29:46 +0100 Subject: [PATCH 024/189] Move packages Signed-off-by: alperozturk --- .../files/downloader/DownloaderServiceTest.kt | 1 + .../client/files/downloader/RegistryTest.kt | 5 ++ .../TransferManagerConnectionTest.kt | 6 +++ .../files/downloader/TransferManagerTest.kt | 8 ++- .../android/files/FileMenuFilterIT.kt | 4 +- .../ui/activity/FolderPickerActivityIT.java | 1 - .../java/com/nextcloud/test/TestActivity.kt | 4 +- app/src/main/AndroidManifest.xml | 2 +- .../com/nextcloud/client/di/AppComponent.java | 4 +- .../nextcloud/client/di/ComponentsModule.java | 4 +- .../com/nextcloud/client/etm/EtmViewModel.kt | 2 +- .../etm/pages/EtmFileTransferFragment.kt | 8 +-- .../files/{downloader => }/Direction.kt | 2 +- .../client/files/{downloader => }/Registry.kt | 11 +++-- .../client/files/{downloader => }/Request.kt | 11 +++-- .../client/files/downloader/DownloadTask.kt | 49 +++++++++++-------- ...ownloadHelper.kt => FileDownloadHelper.kt} | 2 +- ...nloadIntents.kt => FileDownloadIntents.kt} | 20 ++++---- ...ownloadWorker.kt => FileDownloadWorker.kt} | 12 ++--- .../FileTransferService.kt | 13 +++-- .../{downloader => transfer}/Transfer.kt | 24 +++++---- .../TransferManager.kt | 12 +++-- .../TransferManagerConnection.kt | 12 +++-- .../TransferManagerImpl.kt | 21 +++++--- .../{downloader => transfer}/TransferState.kt | 2 +- .../PostUploadAction.kt | 2 +- .../{downloader => upload}/UploadTask.kt | 9 ++-- .../{downloader => upload}/UploadTrigger.kt | 9 ++-- .../client/jobs/BackgroundJobFactory.kt | 8 +-- .../client/jobs/BackgroundJobManagerImpl.kt | 18 +++---- .../client/jobs/ContactsBackupWork.kt | 8 +-- .../nextcloud/client/jobs/FilesExportWork.kt | 4 +- .../android/files/FileMenuFilter.java | 6 +-- .../operations/SynchronizeFileOperation.java | 4 +- .../SynchronizeFolderOperation.java | 4 +- .../providers/DocumentsStorageProvider.java | 2 +- .../android/services/SyncFolderHandler.java | 16 +++--- .../android/ui/activity/ComponentsGetter.java | 4 +- .../ui/activity/ConflictsResolveActivity.kt | 4 +- .../android/ui/activity/FileActivity.java | 10 ++-- .../ui/activity/FileDisplayActivity.java | 32 ++++++------ .../ui/activity/ManageAccountsActivity.java | 8 +-- .../ui/fragment/FileDetailFragment.java | 8 +-- .../android/ui/fragment/FileFragment.java | 1 - .../contactsbackup/BackupListFragment.java | 10 ++-- .../ui/helpers/FileOperationsHelper.java | 4 +- .../ui/preview/PreviewImageActivity.java | 22 ++++----- .../ui/preview/PreviewMediaFragment.java | 4 +- .../sufficientlysecure/SaveCalendar.java | 10 ++-- 49 files changed, 249 insertions(+), 198 deletions(-) rename app/src/main/java/com/nextcloud/client/files/{downloader => }/Direction.kt (94%) rename app/src/main/java/com/nextcloud/client/files/{downloader => }/Registry.kt (94%) rename app/src/main/java/com/nextcloud/client/files/{downloader => }/Request.kt (95%) rename app/src/main/java/com/nextcloud/client/files/downloader/{FilesDownloadHelper.kt => FileDownloadHelper.kt} (99%) rename app/src/main/java/com/nextcloud/client/files/downloader/{FilesDownloadIntents.kt => FileDownloadIntents.kt} (77%) rename app/src/main/java/com/nextcloud/client/files/downloader/{FilesDownloadWorker.kt => FileDownloadWorker.kt} (97%) rename app/src/main/java/com/nextcloud/client/files/{downloader => transfer}/FileTransferService.kt (93%) rename app/src/main/java/com/nextcloud/client/files/{downloader => transfer}/Transfer.kt (73%) rename app/src/main/java/com/nextcloud/client/files/{downloader => transfer}/TransferManager.kt (91%) rename app/src/main/java/com/nextcloud/client/files/{downloader => transfer}/TransferManagerConnection.kt (94%) rename app/src/main/java/com/nextcloud/client/files/{downloader => transfer}/TransferManagerImpl.kt (92%) rename app/src/main/java/com/nextcloud/client/files/{downloader => transfer}/TransferState.kt (95%) rename app/src/main/java/com/nextcloud/client/files/{downloader => upload}/PostUploadAction.kt (96%) rename app/src/main/java/com/nextcloud/client/files/{downloader => upload}/UploadTask.kt (94%) rename app/src/main/java/com/nextcloud/client/files/{downloader => upload}/UploadTrigger.kt (87%) diff --git a/app/src/androidTest/java/com/nextcloud/client/files/downloader/DownloaderServiceTest.kt b/app/src/androidTest/java/com/nextcloud/client/files/downloader/DownloaderServiceTest.kt index 86029131b3dc..3e01188ca8b4 100644 --- a/app/src/androidTest/java/com/nextcloud/client/files/downloader/DownloaderServiceTest.kt +++ b/app/src/androidTest/java/com/nextcloud/client/files/downloader/DownloaderServiceTest.kt @@ -22,6 +22,7 @@ package com.nextcloud.client.files.downloader import androidx.test.core.app.ApplicationProvider.getApplicationContext import androidx.test.rule.ServiceTestRule import com.nextcloud.client.account.MockUser +import com.nextcloud.client.files.transfer.FileTransferService import io.mockk.MockKAnnotations import org.junit.Assert.assertTrue import org.junit.Before diff --git a/app/src/androidTest/java/com/nextcloud/client/files/downloader/RegistryTest.kt b/app/src/androidTest/java/com/nextcloud/client/files/downloader/RegistryTest.kt index 21f39a484f0d..b4018d7ad477 100644 --- a/app/src/androidTest/java/com/nextcloud/client/files/downloader/RegistryTest.kt +++ b/app/src/androidTest/java/com/nextcloud/client/files/downloader/RegistryTest.kt @@ -20,6 +20,11 @@ package com.nextcloud.client.files.downloader import com.nextcloud.client.account.User +import com.nextcloud.client.files.DownloadRequest +import com.nextcloud.client.files.Registry +import com.nextcloud.client.files.Request +import com.nextcloud.client.files.transfer.Transfer +import com.nextcloud.client.files.transfer.TransferState import com.owncloud.android.datamodel.OCFile import io.mockk.CapturingSlot import io.mockk.MockKAnnotations diff --git a/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerConnectionTest.kt b/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerConnectionTest.kt index d5bbe707058c..b33fa175f4b4 100644 --- a/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerConnectionTest.kt +++ b/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerConnectionTest.kt @@ -22,6 +22,12 @@ package com.nextcloud.client.files.downloader import android.content.ComponentName import android.content.Context import com.nextcloud.client.account.MockUser +import com.nextcloud.client.files.DownloadRequest +import com.nextcloud.client.files.transfer.FileTransferService +import com.nextcloud.client.files.transfer.Transfer +import com.nextcloud.client.files.transfer.TransferManager +import com.nextcloud.client.files.transfer.TransferManagerConnection +import com.nextcloud.client.files.transfer.TransferState import com.owncloud.android.datamodel.OCFile import io.mockk.MockKAnnotations import io.mockk.every diff --git a/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt b/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt index aa69648e8be3..ef5e692d8084 100644 --- a/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt +++ b/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt @@ -23,6 +23,12 @@ import androidx.arch.core.executor.testing.InstantTaskExecutorRule import com.nextcloud.client.account.User import com.nextcloud.client.core.ManualAsyncRunner import com.nextcloud.client.core.OnProgressCallback +import com.nextcloud.client.files.DownloadRequest +import com.nextcloud.client.files.Request +import com.nextcloud.client.files.transfer.Transfer +import com.nextcloud.client.files.transfer.TransferManagerImpl +import com.nextcloud.client.files.transfer.TransferState +import com.nextcloud.client.files.upload.UploadTask import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.common.OwnCloudClient import io.mockk.MockKAnnotations @@ -101,7 +107,7 @@ class TransferManagerTest { private fun createMockTask(): DownloadTask { val task = mockk() - every { task.download(any(), any(), any()) } answers { + every { task.download(any()) } answers { taskProgress.forEach { arg>(1).invoke(it) } diff --git a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt index e031d92ccafe..5e48d0b9647d 100644 --- a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt @@ -23,7 +23,7 @@ package com.owncloud.android.files import androidx.test.core.app.launchActivity import androidx.test.ext.junit.runners.AndroidJUnit4 import com.nextcloud.client.account.User -import com.nextcloud.client.files.downloader.FilesDownloadWorker +import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.test.TestActivity import com.nextcloud.utils.EditorUtils import com.owncloud.android.AbstractIT @@ -62,7 +62,7 @@ class FileMenuFilterIT : AbstractIT() { private lateinit var mockFileUploaderBinder: FileUploader.FileUploaderBinder @MockK - private lateinit var mockFileDownloaderBinder: FilesDownloadWorker.FileDownloaderBinder + private lateinit var mockFileDownloaderBinder: FileDownloadWorker.FileDownloaderBinder @MockK private lateinit var mockOperationsServiceBinder: OperationsService.OperationsServiceBinder diff --git a/app/src/androidTest/java/com/owncloud/android/ui/activity/FolderPickerActivityIT.java b/app/src/androidTest/java/com/owncloud/android/ui/activity/FolderPickerActivityIT.java index dbcda37ecc96..67ede342a2a2 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/activity/FolderPickerActivityIT.java +++ b/app/src/androidTest/java/com/owncloud/android/ui/activity/FolderPickerActivityIT.java @@ -22,7 +22,6 @@ */ import android.content.Intent; -import android.view.View; import com.owncloud.android.AbstractIT; import com.owncloud.android.R; diff --git a/app/src/debug/java/com/nextcloud/test/TestActivity.kt b/app/src/debug/java/com/nextcloud/test/TestActivity.kt index 90c4ecc19a82..ec98df551af0 100644 --- a/app/src/debug/java/com/nextcloud/test/TestActivity.kt +++ b/app/src/debug/java/com/nextcloud/test/TestActivity.kt @@ -25,7 +25,7 @@ import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment import androidx.swiperefreshlayout.widget.SwipeRefreshLayout -import com.nextcloud.client.files.downloader.FilesDownloadWorker +import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.client.network.Connectivity import com.nextcloud.client.network.ConnectivityService import com.nextcloud.utils.EditorUtils @@ -130,7 +130,7 @@ class TestActivity : return null } - override fun getFileDownloaderBinder(): FilesDownloadWorker.FileDownloaderBinder? { + override fun getFileDownloaderBinder(): FileDownloadWorker.FileDownloaderBinder? { return null } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3d9cb464745e..f83f59ef32fd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -394,7 +394,7 @@ android:name=".services.OperationsService" android:exported="false" /> . */ -package com.nextcloud.client.files.downloader +package com.nextcloud.client.files enum class Direction { DOWNLOAD, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/Registry.kt b/app/src/main/java/com/nextcloud/client/files/Registry.kt similarity index 94% rename from app/src/main/java/com/nextcloud/client/files/downloader/Registry.kt rename to app/src/main/java/com/nextcloud/client/files/Registry.kt index e33ef4d1852b..1d6d582a759d 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/Registry.kt +++ b/app/src/main/java/com/nextcloud/client/files/Registry.kt @@ -1,8 +1,9 @@ /* * Nextcloud Android client application * - * @author Chris Narkiewicz - * Copyright (C) 2020 Chris Narkiewicz + * @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 @@ -15,10 +16,12 @@ * 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 . + * along with this program. If not, see . */ -package com.nextcloud.client.files.downloader +package com.nextcloud.client.files +import com.nextcloud.client.files.transfer.Transfer +import com.nextcloud.client.files.transfer.TransferState import com.owncloud.android.datamodel.OCFile import java.util.UUID import kotlin.math.max diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/Request.kt b/app/src/main/java/com/nextcloud/client/files/Request.kt similarity index 95% rename from app/src/main/java/com/nextcloud/client/files/downloader/Request.kt rename to app/src/main/java/com/nextcloud/client/files/Request.kt index 5cf6a26d6397..56ab3d7430c7 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/Request.kt +++ b/app/src/main/java/com/nextcloud/client/files/Request.kt @@ -1,8 +1,9 @@ /* * Nextcloud Android client application * - * @author Chris Narkiewicz - * Copyright (C) 2021 Chris Narkiewicz + * @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 @@ -15,13 +16,15 @@ * 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 . + * along with this program. If not, see . */ -package com.nextcloud.client.files.downloader +package com.nextcloud.client.files import android.os.Parcel import android.os.Parcelable import com.nextcloud.client.account.User +import com.nextcloud.client.files.upload.PostUploadAction +import com.nextcloud.client.files.upload.UploadTrigger import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.db.OCUpload diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadTask.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadTask.kt index b8f61045a969..46a1d2e590f7 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadTask.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadTask.kt @@ -21,7 +21,7 @@ package com.nextcloud.client.files.downloader import android.content.ContentResolver import android.content.Context -import com.nextcloud.client.core.IsCancelled +import com.nextcloud.client.files.DownloadRequest import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.common.OwnCloudClient @@ -37,9 +37,9 @@ import java.io.File * This design can be regarded as intermediary refactoring step. */ class DownloadTask( - val context: Context, - val contentResolver: ContentResolver, - val clientProvider: () -> OwnCloudClient + private val context: Context, + private val contentResolver: ContentResolver, + private val clientProvider: () -> OwnCloudClient ) { data class Result(val file: OCFile, val success: Boolean) @@ -62,39 +62,46 @@ class DownloadTask( } } - fun download(request: DownloadRequest, progress: (Int) -> Unit, isCancelled: IsCancelled): Result { + fun download(request: DownloadRequest): Result { val op = DownloadFileOperation(request.user, request.file, context) val client = clientProvider.invoke() val result = op.execute(client) - if (result.isSuccess) { + + return if (result.isSuccess) { val storageManager = FileDataStorageManager( request.user, contentResolver ) val file = saveDownloadedFile(op, storageManager) - return Result(file, true) + Result(file, true) } else { - return Result(request.file, false) + Result(request.file, false) } } private fun saveDownloadedFile(op: DownloadFileOperation, storageManager: FileDataStorageManager): OCFile { - val file = storageManager.getFileById(op.getFile().getFileId()) as OCFile - val syncDate = System.currentTimeMillis() - file.lastSyncDateForProperties = syncDate - file.lastSyncDateForData = syncDate - file.isUpdateThumbnailNeeded = true - file.modificationTimestamp = op.getModificationTimestamp() - file.modificationTimestampAtLastSyncForData = op.getModificationTimestamp() - file.etag = op.getEtag() - file.mimeType = op.getMimeType() - file.storagePath = op.getSavePath() - file.fileLength = File(op.getSavePath()).length() - file.remoteId = op.getFile().getRemoteId() + val file = storageManager.getFileById(op.file.fileId) as OCFile + + file.apply { + val syncDate = System.currentTimeMillis() + lastSyncDateForProperties = syncDate + lastSyncDateForData = syncDate + isUpdateThumbnailNeeded = true + modificationTimestamp = op.modificationTimestamp + modificationTimestampAtLastSyncForData = op.modificationTimestamp + etag = op.etag + mimeType = op.mimeType + storagePath = op.savePath + fileLength = File(op.savePath).length() + remoteId = op.file.remoteId + } + storageManager.saveFile(file) - if (MimeTypeUtil.isMedia(op.getMimeType())) { + + if (MimeTypeUtil.isMedia(op.mimeType)) { FileDataStorageManager.triggerMediaScan(file.storagePath) } + return file } } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt similarity index 99% rename from app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt rename to app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 328d4b4b164d..bd8b8417d9ea 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -33,7 +33,7 @@ import com.owncloud.android.utils.MimeTypeUtil import java.io.File import javax.inject.Inject -class FilesDownloadHelper { +class FileDownloadHelper { @Inject lateinit var backgroundJobManager: BackgroundJobManager diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt similarity index 77% rename from app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt rename to app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt index d8d6e67a2c8f..9725bbd69dda 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt @@ -32,16 +32,16 @@ import com.owncloud.android.ui.fragment.OCFileListFragment import com.owncloud.android.ui.preview.PreviewImageActivity import com.owncloud.android.ui.preview.PreviewImageFragment -class FilesDownloadIntents(private val context: Context) { +class FileDownloadIntents(private val context: Context) { fun newDownloadIntent( download: DownloadFileOperation, linkedToRemotePath: String ): Intent { - return Intent(FilesDownloadWorker.getDownloadAddedMessage()).apply { - putExtra(FilesDownloadWorker.ACCOUNT_NAME, download.user.accountName) - putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) - putExtra(FilesDownloadWorker.EXTRA_LINKED_TO_PATH, linkedToRemotePath) + return Intent(FileDownloadWorker.getDownloadAddedMessage()).apply { + putExtra(FileDownloadWorker.ACCOUNT_NAME, download.user.accountName) + putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) + putExtra(FileDownloadWorker.EXTRA_LINKED_TO_PATH, linkedToRemotePath) setPackage(context.packageName) } } @@ -51,15 +51,15 @@ class FilesDownloadIntents(private val context: Context) { downloadResult: RemoteOperationResult<*>, unlinkedFromRemotePath: String? ): Intent { - return Intent(FilesDownloadWorker.getDownloadFinishMessage()).apply { - putExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) - putExtra(FilesDownloadWorker.ACCOUNT_NAME, download.user.accountName) - putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) + return Intent(FileDownloadWorker.getDownloadFinishMessage()).apply { + putExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) + putExtra(FileDownloadWorker.ACCOUNT_NAME, download.user.accountName) + putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) if (unlinkedFromRemotePath != null) { - putExtra(FilesDownloadWorker.EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) + putExtra(FileDownloadWorker.EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) } setPackage(context.packageName) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt similarity index 97% rename from app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt rename to app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 79bd327cc50a..65afdab5f26c 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -55,7 +55,7 @@ import java.util.AbstractList import java.util.Vector @Suppress("LongParameterList") -class FilesDownloadWorker( +class FileDownloadWorker( private val viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, private val uploadsStorageManager: UploadsStorageManager, @@ -65,7 +65,7 @@ class FilesDownloadWorker( ) : Worker(context, params), OnAccountsUpdateListener, OnDatatransferProgressListener { companion object { - private val TAG = FilesDownloadWorker::class.java.simpleName + private val TAG = FileDownloadWorker::class.java.simpleName const val USER_NAME = "USER" const val FILE = "FILE" @@ -82,23 +82,23 @@ class FilesDownloadWorker( const val ACCOUNT_NAME = "ACCOUNT_NAME" fun getDownloadAddedMessage(): String { - return FilesDownloadWorker::class.java.name + "DOWNLOAD_ADDED" + return FileDownloadWorker::class.java.name + "DOWNLOAD_ADDED" } fun getDownloadFinishMessage(): String { - return FilesDownloadWorker::class.java.name + "DOWNLOAD_FINISH" + return FileDownloadWorker::class.java.name + "DOWNLOAD_FINISH" } } private var currentDownload: DownloadFileOperation? = null private var conflictUploadId: Long? = null private var lastPercent = 0 - private val intents = FilesDownloadIntents(context) + private val intents = FileDownloadIntents(context) private val notificationManager = DownloadNotificationManager(context, viewThemeUtils) private val pendingDownloads = IndexedForest() private var downloadBinder: IBinder = FileDownloaderBinder() private var currentUser = Optional.empty() - private val helper = FilesDownloadHelper() + private val helper = FileDownloadHelper() private var startedDownload = false private var storageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileTransferService.kt b/app/src/main/java/com/nextcloud/client/files/transfer/FileTransferService.kt similarity index 93% rename from app/src/main/java/com/nextcloud/client/files/downloader/FileTransferService.kt rename to app/src/main/java/com/nextcloud/client/files/transfer/FileTransferService.kt index c9b2f7c300b6..daa240c4e7fa 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileTransferService.kt +++ b/app/src/main/java/com/nextcloud/client/files/transfer/FileTransferService.kt @@ -1,8 +1,9 @@ /* * Nextcloud Android client application * - * @author Chris Narkiewicz - * Copyright (C) 2021 Chris Narkiewicz + * @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 @@ -15,9 +16,9 @@ * 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 . + * along with this program. If not, see . */ -package com.nextcloud.client.files.downloader +package com.nextcloud.client.files.transfer import android.app.Service import android.content.Context @@ -27,6 +28,10 @@ import com.nextcloud.client.account.User import com.nextcloud.client.core.AsyncRunner import com.nextcloud.client.core.LocalBinder import com.nextcloud.client.device.PowerManagementService +import com.nextcloud.client.files.Direction +import com.nextcloud.client.files.Request +import com.nextcloud.client.files.downloader.DownloadTask +import com.nextcloud.client.files.upload.UploadTask import com.nextcloud.client.logger.Logger import com.nextcloud.client.network.ClientFactory import com.nextcloud.client.network.ConnectivityService diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/Transfer.kt b/app/src/main/java/com/nextcloud/client/files/transfer/Transfer.kt similarity index 73% rename from app/src/main/java/com/nextcloud/client/files/downloader/Transfer.kt rename to app/src/main/java/com/nextcloud/client/files/transfer/Transfer.kt index fff6c420f730..4b5524b093b0 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/Transfer.kt +++ b/app/src/main/java/com/nextcloud/client/files/transfer/Transfer.kt @@ -1,8 +1,9 @@ -/** +/* * Nextcloud Android client application * - * @author Chris Narkiewicz - * Copyright (C) 2021 Chris Narkiewicz + * @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 @@ -15,10 +16,14 @@ * 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 . + * along with this program. If not, see . */ -package com.nextcloud.client.files.downloader +package com.nextcloud.client.files.transfer +import com.nextcloud.client.files.Direction +import com.nextcloud.client.files.DownloadRequest +import com.nextcloud.client.files.Request +import com.nextcloud.client.files.UploadRequest import com.owncloud.android.datamodel.OCFile import java.util.UUID @@ -48,8 +53,9 @@ data class Transfer( */ val isFinished: Boolean get() = state == TransferState.COMPLETED || state == TransferState.FAILED - val direction: Direction get() = when (request) { - is DownloadRequest -> Direction.DOWNLOAD - is UploadRequest -> Direction.UPLOAD - } + val direction: Direction + get() = when (request) { + is DownloadRequest -> Direction.DOWNLOAD + is UploadRequest -> Direction.UPLOAD + } } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/TransferManager.kt b/app/src/main/java/com/nextcloud/client/files/transfer/TransferManager.kt similarity index 91% rename from app/src/main/java/com/nextcloud/client/files/downloader/TransferManager.kt rename to app/src/main/java/com/nextcloud/client/files/transfer/TransferManager.kt index 957e4928771d..d5a96440a45c 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/TransferManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/transfer/TransferManager.kt @@ -1,8 +1,9 @@ -/** +/* * Nextcloud Android client application * - * @author Chris Narkiewicz - * Copyright (C) 2021 Chris Narkiewicz + * @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 @@ -15,10 +16,11 @@ * 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 . + * along with this program. If not, see . */ -package com.nextcloud.client.files.downloader +package com.nextcloud.client.files.transfer +import com.nextcloud.client.files.Request import com.owncloud.android.datamodel.OCFile import java.util.UUID diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/TransferManagerConnection.kt b/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerConnection.kt similarity index 94% rename from app/src/main/java/com/nextcloud/client/files/downloader/TransferManagerConnection.kt rename to app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerConnection.kt index be2ea7fe45ef..e4cd701e2f72 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/TransferManagerConnection.kt +++ b/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerConnection.kt @@ -1,8 +1,9 @@ -/** +/* * Nextcloud Android client application * - * @author Chris Narkiewicz - * Copyright (C) 2020 Chris Narkiewicz + * @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 @@ -15,15 +16,16 @@ * 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 . + * along with this program. If not, see . */ -package com.nextcloud.client.files.downloader +package com.nextcloud.client.files.transfer import android.content.Context import android.content.Intent import android.os.IBinder import com.nextcloud.client.account.User import com.nextcloud.client.core.LocalConnection +import com.nextcloud.client.files.Request import com.owncloud.android.datamodel.OCFile import java.util.UUID diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/TransferManagerImpl.kt b/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerImpl.kt similarity index 92% rename from app/src/main/java/com/nextcloud/client/files/downloader/TransferManagerImpl.kt rename to app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerImpl.kt index c7869ef368de..8ff6fa24822d 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/TransferManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerImpl.kt @@ -1,8 +1,9 @@ /* * Nextcloud Android client application * - * @author Chris Narkiewicz - * Copyright (C) 2020 Chris Narkiewicz + * @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 @@ -15,14 +16,20 @@ * 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 . + * along with this program. If not, see . */ -package com.nextcloud.client.files.downloader +package com.nextcloud.client.files.transfer import com.nextcloud.client.core.AsyncRunner import com.nextcloud.client.core.IsCancelled import com.nextcloud.client.core.OnProgressCallback import com.nextcloud.client.core.TaskFunction +import com.nextcloud.client.files.DownloadRequest +import com.nextcloud.client.files.Registry +import com.nextcloud.client.files.Request +import com.nextcloud.client.files.UploadRequest +import com.nextcloud.client.files.downloader.DownloadTask +import com.nextcloud.client.files.upload.UploadTask import com.owncloud.android.datamodel.OCFile import com.owncloud.android.operations.UploadFileOperation import java.util.UUID @@ -131,8 +138,8 @@ class TransferManagerImpl( } } else { val downloadTask = downloadTaskFactory.create() - val wrapper: TaskFunction = { progress: ((Int) -> Unit), isCancelled -> - downloadTask.download(request, progress, isCancelled) + val wrapper: TaskFunction = { _: ((Int) -> Unit), _ -> + downloadTask.download(request) } wrapper } @@ -150,7 +157,7 @@ class TransferManagerImpl( } } else { val uploadTask = uploadTaskFactory.create() - val wrapper: TaskFunction = { progress: ((Int) -> Unit), isCancelled -> + val wrapper: TaskFunction = { _: ((Int) -> Unit), _ -> uploadTask.upload(request.user, request.upload) } wrapper diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/TransferState.kt b/app/src/main/java/com/nextcloud/client/files/transfer/TransferState.kt similarity index 95% rename from app/src/main/java/com/nextcloud/client/files/downloader/TransferState.kt rename to app/src/main/java/com/nextcloud/client/files/transfer/TransferState.kt index 0ea69b6cead1..0b9b5a1040b9 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/TransferState.kt +++ b/app/src/main/java/com/nextcloud/client/files/transfer/TransferState.kt @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package com.nextcloud.client.files.downloader +package com.nextcloud.client.files.transfer enum class TransferState { PENDING, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/PostUploadAction.kt b/app/src/main/java/com/nextcloud/client/files/upload/PostUploadAction.kt similarity index 96% rename from app/src/main/java/com/nextcloud/client/files/downloader/PostUploadAction.kt rename to app/src/main/java/com/nextcloud/client/files/upload/PostUploadAction.kt index 0a670eb5b259..91576c379a40 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/PostUploadAction.kt +++ b/app/src/main/java/com/nextcloud/client/files/upload/PostUploadAction.kt @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -package com.nextcloud.client.files.downloader +package com.nextcloud.client.files.upload import com.owncloud.android.files.services.FileUploader diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/UploadTask.kt b/app/src/main/java/com/nextcloud/client/files/upload/UploadTask.kt similarity index 94% rename from app/src/main/java/com/nextcloud/client/files/downloader/UploadTask.kt rename to app/src/main/java/com/nextcloud/client/files/upload/UploadTask.kt index 6c13436a5438..f7011a470c3f 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/UploadTask.kt +++ b/app/src/main/java/com/nextcloud/client/files/upload/UploadTask.kt @@ -1,8 +1,9 @@ /* * Nextcloud Android client application * - * @author Chris Narkiewicz - * Copyright (C) 2021 Chris Narkiewicz + * @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 @@ -15,9 +16,9 @@ * 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 . + * along with this program. If not, see . */ -package com.nextcloud.client.files.downloader +package com.nextcloud.client.files.upload import android.content.Context import com.nextcloud.client.account.User diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/UploadTrigger.kt b/app/src/main/java/com/nextcloud/client/files/upload/UploadTrigger.kt similarity index 87% rename from app/src/main/java/com/nextcloud/client/files/downloader/UploadTrigger.kt rename to app/src/main/java/com/nextcloud/client/files/upload/UploadTrigger.kt index c71802229bb9..a285d9b09168 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/UploadTrigger.kt +++ b/app/src/main/java/com/nextcloud/client/files/upload/UploadTrigger.kt @@ -1,8 +1,9 @@ /* * Nextcloud Android client application * - * @author Chris Narkiewicz - * Copyright (C) 2021 Chris Narkiewicz + * @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 @@ -15,9 +16,9 @@ * 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 . + * along with this program. If not, see . */ -package com.nextcloud.client.files.downloader +package com.nextcloud.client.files.upload import com.owncloud.android.operations.UploadFileOperation diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt index 38debc763eed..865b787d5312 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt @@ -34,7 +34,7 @@ import com.nextcloud.client.device.DeviceInfo import com.nextcloud.client.device.PowerManagementService import com.nextcloud.client.documentscan.GeneratePDFUseCase import com.nextcloud.client.documentscan.GeneratePdfFromImagesWork -import com.nextcloud.client.files.downloader.FilesDownloadWorker +import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.client.integrations.deck.DeckApi import com.nextcloud.client.logger.Logger import com.nextcloud.client.network.ConnectivityService @@ -103,7 +103,7 @@ class BackgroundJobFactory @Inject constructor( CalendarImportWork::class -> createCalendarImportWork(context, workerParameters) FilesExportWork::class -> createFilesExportWork(context, workerParameters) FilesUploadWorker::class -> createFilesUploadWorker(context, workerParameters) - FilesDownloadWorker::class -> createFilesDownloadWorker(context, workerParameters) + FileDownloadWorker::class -> createFilesDownloadWorker(context, workerParameters) GeneratePdfFromImagesWork::class -> createPDFGenerateWork(context, workerParameters) HealthStatusWork::class -> createHealthStatusWork(context, workerParameters) TestJob::class -> createTestJob(context, workerParameters) @@ -255,8 +255,8 @@ class BackgroundJobFactory @Inject constructor( ) } - private fun createFilesDownloadWorker(context: Context, params: WorkerParameters): FilesDownloadWorker { - return FilesDownloadWorker( + private fun createFilesDownloadWorker(context: Context, params: WorkerParameters): FileDownloadWorker { + return FileDownloadWorker( viewThemeUtils.get(), accountManager, uploadsStorageManager, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index f31f41722311..8e815432c97a 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -39,7 +39,7 @@ import com.nextcloud.client.account.User import com.nextcloud.client.core.Clock import com.nextcloud.client.di.Injectable import com.nextcloud.client.documentscan.GeneratePdfFromImagesWork -import com.nextcloud.client.files.downloader.FilesDownloadWorker +import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.client.preferences.AppPreferences import com.owncloud.android.datamodel.OCFile import com.owncloud.android.operations.DownloadType @@ -521,16 +521,16 @@ internal class BackgroundJobManagerImpl( val gson = Gson() val data = workDataOf( - FilesDownloadWorker.USER_NAME to user.accountName, - FilesDownloadWorker.FILE to gson.toJson(ocFile), - FilesDownloadWorker.BEHAVIOUR to behaviour, - FilesDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), - FilesDownloadWorker.ACTIVITY_NAME to activityName, - FilesDownloadWorker.PACKAGE_NAME to packageName, - FilesDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId + FileDownloadWorker.USER_NAME to user.accountName, + FileDownloadWorker.FILE to gson.toJson(ocFile), + FileDownloadWorker.BEHAVIOUR to behaviour, + FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), + FileDownloadWorker.ACTIVITY_NAME to activityName, + FileDownloadWorker.PACKAGE_NAME to packageName, + FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId ) - val request = oneTimeRequestBuilder(FilesDownloadWorker::class, JOB_FILES_DOWNLOAD, user) + val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .setInputData(data) .build() diff --git a/app/src/main/java/com/nextcloud/client/jobs/ContactsBackupWork.kt b/app/src/main/java/com/nextcloud/client/jobs/ContactsBackupWork.kt index e3f7b708b303..8a09e0799750 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/ContactsBackupWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/ContactsBackupWork.kt @@ -35,10 +35,10 @@ import androidx.work.Worker import androidx.work.WorkerParameters import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager -import com.nextcloud.client.files.downloader.PostUploadAction -import com.nextcloud.client.files.downloader.TransferManagerConnection -import com.nextcloud.client.files.downloader.UploadRequest -import com.nextcloud.client.files.downloader.UploadTrigger +import com.nextcloud.client.files.UploadRequest +import com.nextcloud.client.files.transfer.TransferManagerConnection +import com.nextcloud.client.files.upload.PostUploadAction +import com.nextcloud.client.files.upload.UploadTrigger import com.owncloud.android.R import com.owncloud.android.datamodel.ArbitraryDataProvider import com.owncloud.android.datamodel.FileDataStorageManager diff --git a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt index 797cea1969e4..c5f82cc89df2 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt @@ -33,7 +33,7 @@ import androidx.core.app.NotificationCompat import androidx.work.Worker import androidx.work.WorkerParameters import com.nextcloud.client.account.User -import com.nextcloud.client.files.downloader.FilesDownloadHelper +import com.nextcloud.client.files.downloader.FileDownloadHelper import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -111,7 +111,7 @@ class FilesExportWork( } private fun downloadFile(ocFile: OCFile) { - FilesDownloadHelper().downloadFile( + FileDownloadHelper().downloadFile( user, ocFile, DownloadType.EXPORT diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index e1d9ead64139..f3da5e4b807c 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -31,7 +31,7 @@ import com.nextcloud.android.files.FileLockingHelper; import com.nextcloud.client.account.User; import com.nextcloud.client.editimage.EditImageActivity; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.utils.EditorUtils; import com.owncloud.android.R; import com.owncloud.android.datamodel.FileDataStorageManager; @@ -380,7 +380,7 @@ private boolean anyFileSynchronizing() { if (componentsGetter != null && !files.isEmpty() && user != null) { OperationsServiceBinder opsBinder = componentsGetter.getOperationsServiceBinder(); FileUploaderBinder uploaderBinder = componentsGetter.getFileUploaderBinder(); - FilesDownloadWorker.FileDownloaderBinder downloaderBinder = componentsGetter.getFileDownloaderBinder(); + FileDownloadWorker.FileDownloaderBinder downloaderBinder = componentsGetter.getFileDownloaderBinder(); synchronizing = anyFileSynchronizing(opsBinder) || // comparing local and remote anyFileDownloading(downloaderBinder) || anyFileUploading(uploaderBinder); @@ -398,7 +398,7 @@ private boolean anyFileSynchronizing(OperationsServiceBinder opsBinder) { return synchronizing; } - private boolean anyFileDownloading(FilesDownloadWorker.FileDownloaderBinder downloaderBinder) { + private boolean anyFileDownloading(FileDownloadWorker.FileDownloaderBinder downloaderBinder) { boolean downloading = false; if (downloaderBinder != null) { for (Iterator iterator = files.iterator(); !downloading && iterator.hasNext(); ) { diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java index 1d9228dab52d..48b7aa9b701f 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -25,7 +25,7 @@ import android.text.TextUtils; import com.nextcloud.client.account.User; -import com.nextcloud.client.files.downloader.FilesDownloadHelper; +import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileUploader; @@ -316,7 +316,7 @@ private void requestForUpload(OCFile file) { * @param file OCFile object representing the file to download */ private void requestForDownload(OCFile file) { - FilesDownloadHelper downloadHelper = new FilesDownloadHelper(); + FileDownloadHelper downloadHelper = new FileDownloadHelper(); downloadHelper.downloadFile( mUser, diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index 8aa1e07a765e..cf60dacea912 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -25,7 +25,7 @@ import android.text.TextUtils; import com.nextcloud.client.account.User; -import com.nextcloud.client.files.downloader.FilesDownloadHelper; +import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.owncloud.android.datamodel.DecryptedFolderMetadata; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; @@ -452,7 +452,7 @@ private void startDirectDownloads() throws OperationCancelledException { throw new OperationCancelledException(); } - FilesDownloadHelper downloadHelper = new FilesDownloadHelper(); + FileDownloadHelper downloadHelper = new FileDownloadHelper(); downloadHelper.downloadFile(user, file); } diff --git a/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java b/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java index a7f10ffac956..24887f50587e 100644 --- a/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java +++ b/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java @@ -307,7 +307,7 @@ private boolean hasServerChange(Document document) throws FileNotFoundException /** * Updates the OC File after a successful download. * - * TODO unify with code from {@link com.nextcloud.client.files.downloader.FilesDownloadWorker} and {@link DownloadTask}. + * TODO unify with code from {@link com.nextcloud.client.files.downloader.FileDownloadWorker} and {@link DownloadTask}. */ private void saveDownloadedFile(FileDataStorageManager storageManager, DownloadFileOperation dfo, OCFile file) { long syncDate = System.currentTimeMillis(); diff --git a/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java b/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java index 18329af5dc5d..c91702076d5b 100644 --- a/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java +++ b/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java @@ -28,7 +28,7 @@ import android.util.Pair; import com.nextcloud.client.account.User; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.IndexedForest; import com.owncloud.android.lib.common.OwnCloudAccount; @@ -169,9 +169,9 @@ public void cancel(Account account, OCFile file){ * this is a fast and ugly patch. */ private void sendBroadcastNewSyncFolder(Account account, String remotePath) { - Intent added = new Intent(FilesDownloadWorker.Companion.getDownloadAddedMessage()); - added.putExtra(FilesDownloadWorker.ACCOUNT_NAME, account.name); - added.putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, remotePath); + Intent added = new Intent(FileDownloadWorker.Companion.getDownloadAddedMessage()); + added.putExtra(FileDownloadWorker.ACCOUNT_NAME, account.name); + added.putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, remotePath); added.setPackage(mService.getPackageName()); LocalBroadcastManager.getInstance(mService.getApplicationContext()).sendBroadcast(added); } @@ -182,10 +182,10 @@ private void sendBroadcastNewSyncFolder(Account account, String remotePath) { */ private void sendBroadcastFinishedSyncFolder(Account account, String remotePath, boolean success) { - Intent finished = new Intent(FilesDownloadWorker.Companion.getDownloadFinishMessage()); - finished.putExtra(FilesDownloadWorker.ACCOUNT_NAME, account.name); - finished.putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, remotePath); - finished.putExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, success); + Intent finished = new Intent(FileDownloadWorker.Companion.getDownloadFinishMessage()); + finished.putExtra(FileDownloadWorker.ACCOUNT_NAME, account.name); + finished.putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, remotePath); + finished.putExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, success); finished.setPackage(mService.getPackageName()); LocalBroadcastManager.getInstance(mService.getApplicationContext()).sendBroadcast(finished); } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java index 9ae88f3c7248..48cc4986a99e 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java @@ -20,7 +20,7 @@ package com.owncloud.android.ui.activity; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.services.OperationsService.OperationsServiceBinder; @@ -32,7 +32,7 @@ public interface ComponentsGetter { * To be invoked when the parent activity is fully created to get a reference * to the FileDownloadWorker. */ - public FilesDownloadWorker.FileDownloaderBinder getFileDownloaderBinder(); + public FileDownloadWorker.FileDownloaderBinder getFileDownloaderBinder(); /** diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt index 5d18e9698380..0a1f8d3bffbe 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt @@ -21,7 +21,7 @@ import android.content.Intent import android.os.Bundle import android.widget.Toast import com.nextcloud.client.account.User -import com.nextcloud.client.files.downloader.FilesDownloadHelper +import com.nextcloud.client.files.downloader.FileDownloadHelper import com.nextcloud.model.HTTPStatusCodes import com.nextcloud.utils.extensions.getParcelableArgument import com.owncloud.android.R @@ -115,7 +115,7 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener Decision.KEEP_SERVER -> if (!shouldDeleteLocal()) { // Overwrite local file file?.let { - FilesDownloadHelper().downloadFile( + FileDownloadHelper().downloadFile( getUser().orElseThrow { RuntimeException() }, file, conflictUploadId diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index e36c0e9ed2ca..f0c1573cc293 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -43,8 +43,8 @@ import com.google.android.material.snackbar.Snackbar; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; -import com.nextcloud.client.files.downloader.FilesDownloadHelper; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadHelper; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.utils.EditorUtils; @@ -166,7 +166,7 @@ public abstract class FileActivity extends DrawerActivity private boolean mResumed; - protected FilesDownloadWorker.FileDownloaderBinder mDownloaderBinder; + protected FileDownloadWorker.FileDownloaderBinder mDownloaderBinder; protected FileUploaderBinder mUploaderBinder; private ServiceConnection mUploadServiceConnection; @@ -234,7 +234,7 @@ protected void onCreate(Bundle savedInstanceState) { Context.BIND_AUTO_CREATE); if (user != null) { - new FilesDownloadHelper().downloadFile(user, mFile); + new FileDownloadHelper().downloadFile(user, mFile); } mUploadServiceConnection = newTransferenceServiceConnection(); @@ -612,7 +612,7 @@ public void onServiceDisconnected(ComponentName component) { } @Override - public FilesDownloadWorker.FileDownloaderBinder getFileDownloaderBinder() { + public FileDownloadWorker.FileDownloaderBinder getFileDownloaderBinder() { return mDownloaderBinder; } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 7e110b45a2c9..5b757c5a88d1 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -65,8 +65,8 @@ import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; import com.nextcloud.client.files.DeepLinkHandler; -import com.nextcloud.client.files.downloader.FilesDownloadHelper; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadHelper; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.media.PlayerServiceConnection; import com.nextcloud.client.network.ClientFactory; import com.nextcloud.client.network.ConnectivityService; @@ -685,12 +685,12 @@ protected void refreshDetailsFragmentIfVisible(String downloadEvent, String down // the user browsed to other file ; forget the automatic preview mWaitingToPreview = null; - } else if (downloadEvent.equals(FilesDownloadWorker.Companion.getDownloadAddedMessage())) { + } else if (downloadEvent.equals(FileDownloadWorker.Companion.getDownloadAddedMessage())) { // grant that the details fragment updates the progress bar detailsFragment.listenForTransferProgress(); detailsFragment.updateFileDetails(true, false); - } else if (downloadEvent.equals(FilesDownloadWorker.Companion.getDownloadFinishMessage())) { + } else if (downloadEvent.equals(FileDownloadWorker.Companion.getDownloadFinishMessage())) { // update the details panel boolean detailsFragmentChanged = false; if (waitedPreview) { @@ -1116,8 +1116,8 @@ protected void onResume() { localBroadcastManager.registerReceiver(mUploadFinishReceiver, uploadIntentFilter); // Listen for download messages - IntentFilter downloadIntentFilter = new IntentFilter(FilesDownloadWorker.Companion.getDownloadAddedMessage()); - downloadIntentFilter.addAction(FilesDownloadWorker.Companion.getDownloadFinishMessage()); + IntentFilter downloadIntentFilter = new IntentFilter(FileDownloadWorker.Companion.getDownloadAddedMessage()); + downloadIntentFilter.addAction(FileDownloadWorker.Companion.getDownloadFinishMessage()); mDownloadFinishReceiver = new DownloadFinishReceiver(); localBroadcastManager.registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); @@ -1418,7 +1418,7 @@ private boolean isAscendant(String linkedToRemotePath) { /** - * Class waiting for broadcast events from the {@link FilesDownloadWorker} service. + * Class waiting for broadcast events from the {@link FileDownloadWorker} service. *

* Updates the UI when a download is started or finished, provided that it is relevant for the current folder. */ @@ -1427,16 +1427,16 @@ private class DownloadFinishReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { boolean sameAccount = isSameAccount(intent); - String downloadedRemotePath = intent.getStringExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH); + String downloadedRemotePath = intent.getStringExtra(FileDownloadWorker.EXTRA_REMOTE_PATH); String downloadBehaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); boolean isDescendant = isDescendant(downloadedRemotePath); if (sameAccount && isDescendant) { - String linkedToRemotePath = intent.getStringExtra(FilesDownloadWorker.EXTRA_LINKED_TO_PATH); + String linkedToRemotePath = intent.getStringExtra(FileDownloadWorker.EXTRA_LINKED_TO_PATH); if (linkedToRemotePath == null || isAscendant(linkedToRemotePath)) { updateListOfFilesFragment(false); } - refreshDetailsFragmentIfVisible(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, false)); + refreshDetailsFragmentIfVisible(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, false)); } if (mWaitingToSend != null) { @@ -1469,7 +1469,7 @@ private boolean isAscendant(String linkedToRemotePath) { } private boolean isSameAccount(Intent intent) { - String accountName = intent.getStringExtra(FilesDownloadWorker.ACCOUNT_NAME); + String accountName = intent.getStringExtra(FileDownloadWorker.ACCOUNT_NAME); return accountName != null && getAccount() != null && accountName.equals(getAccount().name); } } @@ -1571,9 +1571,9 @@ private class ListServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { - if (component.equals(new ComponentName(FileDisplayActivity.this, FilesDownloadWorker.class))) { + if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloadWorker.class))) { Log_OC.d(TAG, "Download service connected"); - mDownloaderBinder = (FilesDownloadWorker.FileDownloaderBinder) service; + mDownloaderBinder = (FileDownloadWorker.FileDownloaderBinder) service; if (mWaitingToPreview != null && getStorageManager() != null) { // update the file mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); @@ -1604,7 +1604,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { - if (component.equals(new ComponentName(FileDisplayActivity.this, FilesDownloadWorker.class))) { + if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloadWorker.class))) { Log_OC.d(TAG, "Download service disconnected"); mDownloaderBinder = null; } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { @@ -1886,7 +1886,7 @@ private void requestForDownload() { User user = getUser().orElseThrow(RuntimeException::new); //if (!mWaitingToPreview.isDownloading()) { if (!mDownloaderBinder.isDownloading(user, mWaitingToPreview)) { - new FilesDownloadHelper().downloadFile(user, mWaitingToPreview); + new FileDownloadHelper().downloadFile(user, mWaitingToPreview); } } @@ -1958,7 +1958,7 @@ public void run() { private void requestForDownload(OCFile file, String downloadBehaviour, String packageName, String activityName) { final User currentUser = getUser().orElseThrow(RuntimeException::new); if (!mDownloaderBinder.isDownloading(currentUser, mWaitingToPreview)) { - new FilesDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); + new FileDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 24622e11414a..b0d200277393 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -41,7 +41,7 @@ import com.google.common.collect.Sets; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.onboarding.FirstRunActivity; import com.nextcloud.java.util.Optional; @@ -525,8 +525,8 @@ private class ManageAccountsServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { - if (component.equals(new ComponentName(ManageAccountsActivity.this, FilesDownloadWorker.class))) { - mDownloaderBinder = (FilesDownloadWorker.FileDownloaderBinder) service; + if (component.equals(new ComponentName(ManageAccountsActivity.this, FileDownloadWorker.class))) { + mDownloaderBinder = (FileDownloadWorker.FileDownloaderBinder) service; } else if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service connected"); @@ -536,7 +536,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { - if (component.equals(new ComponentName(ManageAccountsActivity.this, FilesDownloadWorker.class))) { + if (component.equals(new ComponentName(ManageAccountsActivity.this, FileDownloadWorker.class))) { Log_OC.d(TAG, "Download service suddenly disconnected"); mDownloaderBinder = null; } else if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 9f16f82dd003..45bebf359d68 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -44,7 +44,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ClientFactory; import com.nextcloud.client.network.ConnectivityService; @@ -502,7 +502,7 @@ public void updateFileDetails(OCFile file, User user) { * TODO Remove parameter when the transferring state of files is kept in database. * * @param transferring Flag signaling if the file should be considered as downloading or uploading, although - * {@link com.nextcloud.client.files.downloader.FilesDownloadWorker.FileDownloaderBinder#isDownloading(User, OCFile)} and + * {@link com.nextcloud.client.files.downloader.FileDownloadWorker.FileDownloaderBinder#isDownloading(User, OCFile)} and * {@link FileUploaderBinder#isUploading(User, OCFile)} return false. * @param refresh If 'true', try to refresh the whole file from the database */ @@ -534,7 +534,7 @@ public void updateFileDetails(boolean transferring, boolean refresh) { setFavoriteIconStatus(file.isFavorite()); // configure UI for depending upon local state of the file - FilesDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); + FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(user, file)) @@ -659,7 +659,7 @@ private void setButtonsForTransferring() { // show the progress bar for the transfer binding.progressBlock.setVisibility(View.VISIBLE); binding.progressText.setVisibility(View.VISIBLE); - FilesDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); + FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); //if (getFile().isDownloading()) { if (downloaderBinder != null && downloaderBinder.isDownloading(user, getFile())) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileFragment.java index e64dd05f2390..34b0d0cbdf58 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileFragment.java @@ -21,7 +21,6 @@ package com.owncloud.android.ui.fragment; -import android.accounts.Account; import android.app.Activity; import android.os.Bundle; diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListFragment.java index 5e1a38e38951..8aad8525c676 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListFragment.java @@ -38,11 +38,11 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; -import com.nextcloud.client.files.downloader.DownloadRequest; -import com.nextcloud.client.files.downloader.Request; -import com.nextcloud.client.files.downloader.Transfer; -import com.nextcloud.client.files.downloader.TransferManagerConnection; -import com.nextcloud.client.files.downloader.TransferState; +import com.nextcloud.client.files.DownloadRequest; +import com.nextcloud.client.files.Request; +import com.nextcloud.client.files.transfer.Transfer; +import com.nextcloud.client.files.transfer.TransferManagerConnection; +import com.nextcloud.client.files.transfer.TransferState; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ClientFactory; import com.nextcloud.utils.extensions.BundleExtensionsKt; diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 8700a80c61f1..08e7416512bf 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -47,7 +47,7 @@ import com.nextcloud.client.account.CurrentAccountProvider; import com.nextcloud.client.account.User; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.java.util.Optional; @@ -997,7 +997,7 @@ public void cancelTransference(OCFile file) { } // for both files and folders - FilesDownloadWorker.FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder(); + FileDownloadWorker.FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder(); if (downloaderBinder != null && downloaderBinder.isDownloading(currentUser, file)) { downloaderBinder.cancelPendingOrCurrentDownloads(currentUser.toPlatformAccount(), file); } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index fe11f92933fc..13363d231fd2 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -37,8 +37,8 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; -import com.nextcloud.client.files.downloader.FilesDownloadHelper; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +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.utils.extensions.IntentExtensionsKt; @@ -311,8 +311,8 @@ private class PreviewImageServiceConnection implements ServiceConnection { public void onServiceConnected(ComponentName component, IBinder service) { if (component.equals(new ComponentName(PreviewImageActivity.this, - FilesDownloadWorker.class))) { - mDownloaderBinder = (FilesDownloadWorker.FileDownloaderBinder) service; + FileDownloadWorker.class))) { + mDownloaderBinder = (FileDownloadWorker.FileDownloaderBinder) service; if (mRequestWaitingForBinder) { mRequestWaitingForBinder = false; Log_OC.d(TAG, "Simulating reselection of current page after connection " + @@ -331,7 +331,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { if (component.equals(new ComponentName(PreviewImageActivity.this, - FilesDownloadWorker.class))) { + FileDownloadWorker.class))) { Log_OC.d(TAG, "Download service suddenly disconnected"); mDownloaderBinder = null; } else if (component.equals(new ComponentName(PreviewImageActivity.this, @@ -359,7 +359,7 @@ protected void onResume() { super.onResume(); mDownloadFinishReceiver = new DownloadFinishReceiver(); - IntentFilter downloadIntentFilter = new IntentFilter(FilesDownloadWorker.Companion.getDownloadFinishMessage()); + IntentFilter downloadIntentFilter = new IntentFilter(FileDownloadWorker.Companion.getDownloadFinishMessage()); localBroadcastManager.registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); mUploadFinishReceiver = new UploadFinishReceiver(); @@ -413,7 +413,7 @@ public void requestForDownload(OCFile file, String downloadBehaviour) { } else if (!mDownloaderBinder.isDownloading(getUserAccountManager().getUser(), file)) { final User user = getUser().orElseThrow(RuntimeException::new); - new FilesDownloadHelper().downloadFile(user, file, downloadBehaviour); + new FileDownloadHelper().downloadFile(user, file, downloadBehaviour); } } @@ -478,7 +478,7 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse } /** - * Class waiting for broadcast events from the {@link FilesDownloadWorker} service. + * Class waiting for broadcast events from the {@link FileDownloadWorker} service. * * Updates the UI when a download is started or finished, provided that it is relevant for the * folder displayed in the gallery. @@ -498,12 +498,12 @@ public void onReceive(Context context, Intent intent) { } private void previewNewImage(Intent intent) { - String accountName = intent.getStringExtra(FilesDownloadWorker.ACCOUNT_NAME); - String downloadedRemotePath = intent.getStringExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH); + String accountName = intent.getStringExtra(FileDownloadWorker.ACCOUNT_NAME); + String downloadedRemotePath = intent.getStringExtra(FileDownloadWorker.EXTRA_REMOTE_PATH); String downloadBehaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); if (getAccount().name.equals(accountName) && downloadedRemotePath != null) { OCFile file = getStorageManager().getFileByPath(downloadedRemotePath); - boolean downloadWasFine = intent.getBooleanExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, false); + boolean downloadWasFine = intent.getBooleanExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, false); if (EditImageActivity.OPEN_IMAGE_EDITOR.equals(downloadBehaviour)) { startImageEditor(file); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index d42ebb0255cc..d4a1bd18c154 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -53,7 +53,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; -import com.nextcloud.client.files.downloader.FilesDownloadHelper; +import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.media.ExoplayerListener; import com.nextcloud.client.media.NextcloudExoPlayer; @@ -479,7 +479,7 @@ public void onFileActionChosen(final int itemId) { backgroundJobManager); } else if (itemId == R.id.action_download_file) { if (!containerActivity.getFileDownloaderBinder().isDownloading(user, getFile())) { - new FilesDownloadHelper().downloadFile(user, getFile()); + new FileDownloadHelper().downloadFile(user, getFile()); } } } diff --git a/app/src/main/java/third_parties/sufficientlysecure/SaveCalendar.java b/app/src/main/java/third_parties/sufficientlysecure/SaveCalendar.java index fcdf8ffc960a..5a3101d9329a 100644 --- a/app/src/main/java/third_parties/sufficientlysecure/SaveCalendar.java +++ b/app/src/main/java/third_parties/sufficientlysecure/SaveCalendar.java @@ -42,11 +42,11 @@ import android.widget.EditText; import com.nextcloud.client.account.User; -import com.nextcloud.client.files.downloader.PostUploadAction; -import com.nextcloud.client.files.downloader.Request; -import com.nextcloud.client.files.downloader.TransferManagerConnection; -import com.nextcloud.client.files.downloader.UploadRequest; -import com.nextcloud.client.files.downloader.UploadTrigger; +import com.nextcloud.client.files.Request; +import com.nextcloud.client.files.UploadRequest; +import com.nextcloud.client.files.transfer.TransferManagerConnection; +import com.nextcloud.client.files.upload.PostUploadAction; +import com.nextcloud.client.files.upload.UploadTrigger; import com.nextcloud.client.preferences.AppPreferences; import com.owncloud.android.R; import com.owncloud.android.datamodel.OCFile; From b9982852addaec2f655e72e2503c181b27dc530a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 26 Dec 2023 13:33:47 +0100 Subject: [PATCH 025/189] Fix tests Signed-off-by: alperozturk --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 29a27ffa5276..c761c2cff1e8 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ buildscript { androidLibraryVersion = "master-SNAPSHOT" mockitoVersion = "4.11.0" mockitoKotlinVersion = "4.1.0" - mockkVersion = "1.13.3" + mockkVersion = "1.13.8" espressoVersion = "3.5.1" workRuntime = "2.8.1" fidoVersion = "4.1.0-patch2" From d6019988583932bc9fae9683ab87a3b30fedf323 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 27 Dec 2023 09:58:27 +0100 Subject: [PATCH 026/189] Fix createMockTask test Signed-off-by: alperozturk --- .../nextcloud/client/files/downloader/TransferManagerTest.kt | 2 +- .../com/nextcloud/client/files/downloader/DownloadTask.kt | 4 +++- .../nextcloud/client/files/transfer/TransferManagerImpl.kt | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt b/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt index ef5e692d8084..39cdf9c02ebd 100644 --- a/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt +++ b/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt @@ -107,7 +107,7 @@ class TransferManagerTest { private fun createMockTask(): DownloadTask { val task = mockk() - every { task.download(any()) } answers { + every { task.download(any(), any(), any()) } answers { taskProgress.forEach { arg>(1).invoke(it) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadTask.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadTask.kt index 46a1d2e590f7..dda1816864e7 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadTask.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadTask.kt @@ -21,6 +21,7 @@ package com.nextcloud.client.files.downloader import android.content.ContentResolver import android.content.Context +import com.nextcloud.client.core.IsCancelled import com.nextcloud.client.files.DownloadRequest import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -62,7 +63,8 @@ class DownloadTask( } } - fun download(request: DownloadRequest): Result { + // Unused progress, isCancelled arguments needed for TransferManagerTest + fun download(request: DownloadRequest, progress: (Int) -> Unit, isCancelled: IsCancelled): Result { val op = DownloadFileOperation(request.user, request.file, context) val client = clientProvider.invoke() val result = op.execute(client) diff --git a/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerImpl.kt b/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerImpl.kt index 8ff6fa24822d..0113002d96d3 100644 --- a/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerImpl.kt @@ -138,8 +138,8 @@ class TransferManagerImpl( } } else { val downloadTask = downloadTaskFactory.create() - val wrapper: TaskFunction = { _: ((Int) -> Unit), _ -> - downloadTask.download(request) + val wrapper: TaskFunction = { progress: ((Int) -> Unit), isCancelled -> + downloadTask.download(request, progress, isCancelled) } wrapper } From 919fd6b85052853de54df8556fb5a693b792bd56 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 27 Dec 2023 14:49:26 +0100 Subject: [PATCH 027/189] Fix Notifications Signed-off-by: alperozturk --- .../files/downloader/FileDownloadWorker.kt | 32 +++++----- .../download/DownloadNotificationManager.kt | 58 +++++++++++-------- 2 files changed, 50 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 65afdab5f26c..48bbc217b94f 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -152,6 +152,7 @@ class FileDownloadWorker( context, downloadType ) + operation.addDatatransferProgressListener(this) operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder) val putResult = pendingDownloads.putIfAbsent( @@ -232,9 +233,11 @@ class FileDownloadWorker( private fun notifyDownloadStart(download: DownloadFileOperation) { lastPercent = 0 - notificationManager.notifyForStart(download) - notificationManager.setContentIntent(intents.detailsIntent(download), PendingIntent.FLAG_IMMUTABLE) - notificationManager.showDownloadInProgressNotification() + notificationManager.run { + notifyForStart(download) + setContentIntent(intents.detailsIntent(download), PendingIntent.FLAG_IMMUTABLE) + showDownloadInProgressNotification() + } } private fun getOCAccountForDownload(): OwnCloudAccount { @@ -285,25 +288,24 @@ class FileDownloadWorker( download: DownloadFileOperation, downloadResult: RemoteOperationResult<*> ) { - if (downloadResult.isCancelled) { - return - } + dismissDownloadInProgressNotification() - if (downloadResult.isSuccess) { - dismissDownloadInProgressNotification() + if (downloadResult.isCancelled) { return } val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) - notificationManager.prepareForResult(downloadResult, needsToUpdateCredentials) + notificationManager.run { + prepareForResult(downloadResult, needsToUpdateCredentials) - if (needsToUpdateCredentials) { - notificationManager.setCredentialContentIntent(download.user) - } else { - notificationManager.setContentIntent(intents.detailsIntent(null), PendingIntent.FLAG_IMMUTABLE) - } + if (needsToUpdateCredentials) { + setCredentialContentIntent(download.user) + } else { + setContentIntent(intents.detailsIntent(null), PendingIntent.FLAG_IMMUTABLE) + } - notificationManager.notifyForResult(downloadResult, download) + notifyForResult(downloadResult, download) + } } private fun dismissDownloadInProgressNotification() { diff --git a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt index 0bd056e19cbb..63c9731b046d 100644 --- a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt @@ -83,41 +83,49 @@ class DownloadNotificationManager(private val context: Context, private val view @Suppress("MagicNumber") fun notifyForResult(result: RemoteOperationResult<*>, download: DownloadFileOperation) { - val errorMessage = ErrorMessageAdapter.getErrorCauseMessage( - result, - download, - context.resources - ) - - notificationBuilder.setContentText(errorMessage) - - notificationManager.notify(SecureRandom().nextInt(), notificationBuilder.build()) + val tickerId = getTickerId(result.isSuccess, null) + val notifyId = SecureRandom().nextInt() - if (result.isSuccess) { - NotificationUtils.cancelWithDelay( - notificationManager, - R.string.downloader_download_succeeded_ticker, - 2000 + val contentText = if (result.isSuccess) { + context.getString(R.string.downloader_download_succeeded_ticker) + } else { + ErrorMessageAdapter.getErrorCauseMessage( + result, + download, + context.resources ) } + + notificationBuilder.run { + setTicker(context.getString(tickerId)) + setContentText(contentText) + notificationManager.notify(notifyId, this.build()) + } + + NotificationUtils.cancelWithDelay( + notificationManager, + notifyId, + 2000 + ) } - fun prepareForResult( - downloadResult: RemoteOperationResult<*>, - needsToUpdateCredentials: Boolean - ) { - var tickerId = - if (downloadResult.isSuccess) { + private fun getTickerId(isSuccess: Boolean, needsToUpdateCredentials: Boolean?): Int { + return if (needsToUpdateCredentials == true) { + R.string.downloader_download_failed_credentials_error + } else { + if (isSuccess) { R.string.downloader_download_succeeded_ticker } else { R.string.downloader_download_failed_ticker } - - tickerId = if (needsToUpdateCredentials) { - R.string.downloader_download_failed_credentials_error - } else { - tickerId } + } + + fun prepareForResult( + downloadResult: RemoteOperationResult<*>, + needsToUpdateCredentials: Boolean + ) { + val tickerId = getTickerId(downloadResult.isSuccess, needsToUpdateCredentials) notificationBuilder .setTicker(context.getString(tickerId)) From 589f9561b298da9f00aa3c638f2470ebc651aa3f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 27 Dec 2023 14:50:41 +0100 Subject: [PATCH 028/189] Add TODO for some unknown code block Signed-off-by: alperozturk --- .../com/nextcloud/client/files/downloader/FileDownloadWorker.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 48bbc217b94f..3db6196dceda 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -309,6 +309,7 @@ class FileDownloadWorker( } private fun dismissDownloadInProgressNotification() { + // TODO Check necessity of this function call conflictUploadId?.let { if (it > 0) { uploadsStorageManager.removeUpload(it) From 9b124d402b03ba3a07dcbc02ccca3897fd612551 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 27 Dec 2023 14:54:40 +0100 Subject: [PATCH 029/189] Add TODO for some unknown code block Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadWorker.kt | 8 ++++++-- .../notifications/download/DownloadNotificationManager.kt | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 3db6196dceda..6e1ef43431cd 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -288,12 +288,16 @@ class FileDownloadWorker( download: DownloadFileOperation, downloadResult: RemoteOperationResult<*> ) { - dismissDownloadInProgressNotification() - if (downloadResult.isCancelled) { return } + // TODO Check why we calling only for success? + if (downloadResult.isSuccess) { + dismissDownloadInProgressNotification() + return + } + val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) notificationManager.run { prepareForResult(downloadResult, needsToUpdateCredentials) diff --git a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt index 63c9731b046d..51bace7e6728 100644 --- a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt @@ -83,6 +83,8 @@ class DownloadNotificationManager(private val context: Context, private val view @Suppress("MagicNumber") fun notifyForResult(result: RemoteOperationResult<*>, download: DownloadFileOperation) { + dismissDownloadInProgressNotification() + val tickerId = getTickerId(result.isSuccess, null) val notifyId = SecureRandom().nextInt() From f14abd4b8e138327d2928bf2f1d02d49840537f6 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 27 Dec 2023 14:57:59 +0100 Subject: [PATCH 030/189] Remove return Signed-off-by: alperozturk --- .../com/nextcloud/client/files/downloader/FileDownloadWorker.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 6e1ef43431cd..1bdc1ff3518e 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -295,7 +295,6 @@ class FileDownloadWorker( // TODO Check why we calling only for success? if (downloadResult.isSuccess) { dismissDownloadInProgressNotification() - return } val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) From 1c2c56fdd427b3a2b988daa210dd2cef7de2b529 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 27 Dec 2023 15:47:48 +0100 Subject: [PATCH 031/189] Fix sync Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 24 +++++-- .../client/jobs/BackgroundJobManager.kt | 13 ++++ .../client/jobs/BackgroundJobManagerImpl.kt | 72 +++++++++++++++++-- .../SynchronizeFolderOperation.java | 16 +---- 4 files changed, 102 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index bd8b8417d9ea..ecbe944a9af3 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -31,6 +31,7 @@ import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType import com.owncloud.android.utils.MimeTypeUtil import java.io.File +import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject class FileDownloadHelper { @@ -79,8 +80,21 @@ class FileDownloadHelper { storageManager?.saveConflict(file, null) } - fun downloadFile(user: User, ocFile: OCFile) { + fun downloadFiles(user: User, ocFile: List, cancelRequest: AtomicBoolean) { backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + "", + DownloadType.DOWNLOAD, + "", + "", + null, + cancelRequest + ) + } + + fun downloadFile(user: User, ocFile: OCFile) { + backgroundJobManager.startFileDownloadJob( user, ocFile, "", @@ -92,7 +106,7 @@ class FileDownloadHelper { } fun downloadFile(user: User, ocFile: OCFile, behaviour: String) { - backgroundJobManager.startFilesDownloadJob( + backgroundJobManager.startFileDownloadJob( user, ocFile, behaviour, @@ -104,7 +118,7 @@ class FileDownloadHelper { } fun downloadFile(user: User, ocFile: OCFile, downloadType: DownloadType) { - backgroundJobManager.startFilesDownloadJob( + backgroundJobManager.startFileDownloadJob( user, ocFile, "", @@ -116,7 +130,7 @@ class FileDownloadHelper { } fun downloadFile(user: User, ocFile: OCFile, conflictUploadId: Long) { - backgroundJobManager.startFilesDownloadJob( + backgroundJobManager.startFileDownloadJob( user, ocFile, "", @@ -137,7 +151,7 @@ class FileDownloadHelper { packageName: String, conflictUploadId: Long? ) { - backgroundJobManager.startFilesDownloadJob( + backgroundJobManager.startFileDownloadJob( user, ocFile, behaviour, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 30b90d1fbe18..4b2f505c8d3f 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -24,6 +24,7 @@ import androidx.work.ListenableWorker import com.nextcloud.client.account.User import com.owncloud.android.datamodel.OCFile import com.owncloud.android.operations.DownloadType +import java.util.concurrent.atomic.AtomicBoolean /** * This interface allows to control, schedule and monitor all application @@ -147,6 +148,18 @@ interface BackgroundJobManager { @Suppress("LongParameterList") fun startFilesDownloadJob( + user: User, + files: List, + behaviour: String, + downloadType: DownloadType?, + activityName: String, + packageName: String, + conflictUploadId: Long?, + cancelRequest: AtomicBoolean + ) + + @Suppress("LongParameterList") + fun startFileDownloadJob( user: User, ocFile: OCFile, behaviour: String, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 8e815432c97a..98d67a1c04df 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -42,10 +42,12 @@ import com.nextcloud.client.documentscan.GeneratePdfFromImagesWork import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.client.preferences.AppPreferences import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.lib.common.operations.OperationCancelledException import com.owncloud.android.operations.DownloadType import java.util.Date import java.util.UUID import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicBoolean import kotlin.reflect.KClass /** @@ -509,20 +511,20 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_FILES_UPLOAD + user.accountName, ExistingWorkPolicy.KEEP, request) } - override fun startFilesDownloadJob( + private fun getOneTimeDownloadRequest( user: User, - ocFile: OCFile, + file: OCFile, behaviour: String, downloadType: DownloadType?, activityName: String, packageName: String, conflictUploadId: Long? - ) { + ): OneTimeWorkRequest { val gson = Gson() val data = workDataOf( FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FILE to gson.toJson(ocFile), + FileDownloadWorker.FILE to gson.toJson(file), FileDownloadWorker.BEHAVIOUR to behaviour, FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), FileDownloadWorker.ACTIVITY_NAME to activityName, @@ -530,9 +532,69 @@ internal class BackgroundJobManagerImpl( FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId ) - val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) + return oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .setInputData(data) .build() + } + + @Throws(OperationCancelledException::class) + override fun startFilesDownloadJob( + user: User, + files: List, + behaviour: String, + downloadType: DownloadType?, + activityName: String, + packageName: String, + conflictUploadId: Long?, + cancelRequest: AtomicBoolean + ) { + val workRequestList = mutableListOf() + + for (file in files) { + synchronized(cancelRequest) { + if (cancelRequest.get()) { + throw OperationCancelledException() + } + + workRequestList.add( + getOneTimeDownloadRequest( + user, + file, + behaviour, + downloadType, + activityName, + packageName, + conflictUploadId + ) + ) + } + } + + val chain = workManager + .beginWith(workRequestList.first()) + .then(workRequestList.subList(1, workRequestList.size)) + + chain.enqueue() + } + + override fun startFileDownloadJob( + user: User, + ocFile: OCFile, + behaviour: String, + downloadType: DownloadType?, + activityName: String, + packageName: String, + conflictUploadId: Long? + ) { + val request = getOneTimeDownloadRequest( + user, + ocFile, + behaviour, + downloadType, + activityName, + packageName, + conflictUploadId + ) workManager.enqueueUniqueWork(JOB_FILES_DOWNLOAD + user.accountName, ExistingWorkPolicy.REPLACE, request) } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index cf60dacea912..e69a96821b2f 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -444,19 +444,9 @@ private void syncContents() throws OperationCancelledException { startContentSynchronizations(mFilesToSyncContents); } - - private void startDirectDownloads() throws OperationCancelledException { - for (OCFile file : mFilesForDirectDownload) { - synchronized(mCancellationRequested) { - if (mCancellationRequested.get()) { - throw new OperationCancelledException(); - } - - FileDownloadHelper downloadHelper = new FileDownloadHelper(); - - downloadHelper.downloadFile(user, file); - } - } + private void startDirectDownloads() { + FileDownloadHelper downloadHelper = new FileDownloadHelper(); + downloadHelper.downloadFiles(user, mFilesForDirectDownload, mCancellationRequested); } /** From 60ee1d59adfe26ca8d52003aa9d7388e889129da Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 27 Dec 2023 15:57:34 +0100 Subject: [PATCH 032/189] Fix Code Analytics Signed-off-by: alperozturk --- .../java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 98d67a1c04df..9ce6b3a85d63 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -511,6 +511,7 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_FILES_UPLOAD + user.accountName, ExistingWorkPolicy.KEEP, request) } + @Suppress("LongParameterList") private fun getOneTimeDownloadRequest( user: User, file: OCFile, From efe6649b69ee4b6be63545868ceef8284c550a9c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 28 Dec 2023 09:45:51 +0100 Subject: [PATCH 033/189] Fix FileDownloaderBinder functions Signed-off-by: alperozturk --- .../android/files/FileMenuFilterIT.kt | 2 +- .../files/downloader/FileDownloadWorker.kt | 31 +++++++------------ .../utils/extensions/ContextExtensions.kt | 31 +++++++++++++++++++ .../android/files/FileMenuFilter.java | 2 +- .../ui/activity/FileDisplayActivity.java | 5 ++- .../android/ui/adapter/OCFileListDelegate.kt | 2 +- .../ui/fragment/FileDetailFragment.java | 4 +-- .../ui/helpers/FileOperationsHelper.java | 4 +-- .../ui/preview/PreviewImageActivity.java | 2 +- .../ui/preview/PreviewMediaFragment.java | 2 +- 10 files changed, 53 insertions(+), 32 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt index 5e48d0b9647d..0b7f37bdcee1 100644 --- a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt @@ -77,7 +77,7 @@ class FileMenuFilterIT : AbstractIT() { MockKAnnotations.init(this) every { mockFileUploaderBinder.isUploading(any(), any()) } returns false every { mockComponentsGetter.fileUploaderBinder } returns mockFileUploaderBinder - every { mockFileDownloaderBinder.isDownloading(any(), any()) } returns false + every { mockFileDownloaderBinder.isDownloading() } returns false every { mockComponentsGetter.fileDownloaderBinder } returns mockFileDownloaderBinder every { mockOperationsServiceBinder.isSynchronizing(any(), any()) } returns false every { mockComponentsGetter.operationsServiceBinder } returns mockOperationsServiceBinder diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 1bdc1ff3518e..26fb514d5569 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -28,15 +28,17 @@ import android.app.PendingIntent import android.content.Context import android.os.Binder import android.os.IBinder -import android.util.Pair import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters import com.google.gson.Gson import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.jobs.BackgroundJobManagerImpl.Companion.JOB_FILES_DOWNLOAD import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional +import com.nextcloud.utils.extensions.cancelWork +import com.nextcloud.utils.extensions.isWorkScheduled import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager @@ -338,8 +340,10 @@ class FileDownloadWorker( val percent: Int = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt() if (percent != lastPercent) { - notificationManager.updateDownloadProgressNotification(filePath, percent, totalToTransfer) - notificationManager.showDownloadInProgressNotification() + notificationManager.run { + updateDownloadProgressNotification(filePath, percent, totalToTransfer) + showDownloadInProgressNotification() + } } lastPercent = percent @@ -348,21 +352,8 @@ class FileDownloadWorker( inner class FileDownloaderBinder : Binder(), OnDatatransferProgressListener { private val boundListeners: MutableMap = HashMap() - fun cancelPendingOrCurrentDownloads(account: Account, file: OCFile) { - val removeResult: Pair = - pendingDownloads.remove(account.name, file.remotePath) - val download = removeResult.first - - if (download != null) { - download.cancel() - } else { - if (currentUser?.isPresent == true && - currentDownload?.remotePath?.startsWith(file.remotePath) == true && - account.name == currentUser.get()?.accountName - ) { - currentDownload?.cancel() - } - } + fun cancelPendingOrCurrentDownloads() { + context.cancelWork(JOB_FILES_DOWNLOAD) } fun cancelAllDownloadsForAccount(accountName: String?) { @@ -373,8 +364,8 @@ class FileDownloadWorker( cancelPendingDownloads(accountName) } - fun isDownloading(user: User?, file: OCFile?): Boolean { - return user != null && file != null && pendingDownloads.contains(user.accountName, file.remotePath) + fun isDownloading(): Boolean { + return context.isWorkScheduled(JOB_FILES_DOWNLOAD) } fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt index 6dc7dde71e2f..35527d4af8b1 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt @@ -27,7 +27,12 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.Build +import androidx.work.WorkInfo +import androidx.work.WorkManager +import com.google.common.util.concurrent.ListenableFuture import com.owncloud.android.datamodel.ReceiverFlag +import com.owncloud.android.lib.common.utils.Log_OC +import java.util.concurrent.ExecutionException @SuppressLint("UnspecifiedRegisterReceiverFlag") fun Context.registerBroadcastReceiver(receiver: BroadcastReceiver?, filter: IntentFilter, flag: ReceiverFlag): Intent? { @@ -37,3 +42,29 @@ fun Context.registerBroadcastReceiver(receiver: BroadcastReceiver?, filter: Inte registerReceiver(receiver, filter) } } + +fun Context.isWorkScheduled(tag: String): Boolean { + val instance = WorkManager.getInstance(this) + val statuses: ListenableFuture> = instance.getWorkInfosByTag(tag) + var running = false + var workInfoList: List = emptyList() + + try { + workInfoList = statuses.get() + } catch (e: ExecutionException) { + Log_OC.d("Worker", "ExecutionException in isWorkScheduled: $e") + } catch (e: InterruptedException) { + Log_OC.d("Worker", "InterruptedException in isWorkScheduled: $e") + } + + for (workInfo in workInfoList) { + val state = workInfo.state + running = running || (state == WorkInfo.State.RUNNING || state == WorkInfo.State.ENQUEUED) + } + + return running +} + +fun Context.cancelWork(tag: String) { + WorkManager.getInstance(this).cancelAllWorkByTag(tag) +} diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index f3da5e4b807c..b5e721e4a99f 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -402,7 +402,7 @@ private boolean anyFileDownloading(FileDownloadWorker.FileDownloaderBinder downl boolean downloading = false; if (downloaderBinder != null) { for (Iterator iterator = files.iterator(); !downloading && iterator.hasNext(); ) { - downloading = downloaderBinder.isDownloading(user, iterator.next()); + downloading = downloaderBinder.isDownloading(); } } return downloading; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 5b757c5a88d1..5be55acdd3fb 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1884,8 +1884,7 @@ public void onTransferStateChanged(OCFile file, boolean downloading, boolean upl private void requestForDownload() { User user = getUser().orElseThrow(RuntimeException::new); - //if (!mWaitingToPreview.isDownloading()) { - if (!mDownloaderBinder.isDownloading(user, mWaitingToPreview)) { + if (!mDownloaderBinder.isDownloading()) { new FileDownloadHelper().downloadFile(user, mWaitingToPreview); } } @@ -1957,7 +1956,7 @@ public void run() { private void requestForDownload(OCFile file, String downloadBehaviour, String packageName, String activityName) { final User currentUser = getUser().orElseThrow(RuntimeException::new); - if (!mDownloaderBinder.isDownloading(currentUser, mWaitingToPreview)) { + if (!mDownloaderBinder.isDownloading()) { new FileDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index e350d8b7c856..4be366f9afd8 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -344,7 +344,7 @@ class OCFileListDelegate( val fileUploaderBinder = transferServiceGetter.fileUploaderBinder when { operationsServiceBinder?.isSynchronizing(user, file) == true || - fileDownloaderBinder?.isDownloading(user, file) == true || + fileDownloaderBinder?.isDownloading() == true || fileUploaderBinder?.isUploading(user, file) == true -> { // synchronizing, downloading or uploading gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 45bebf359d68..a152511bb231 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -537,7 +537,7 @@ public void updateFileDetails(boolean transferring, boolean refresh) { FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); if (transferring - || (downloaderBinder != null && downloaderBinder.isDownloading(user, file)) + || (downloaderBinder != null && downloaderBinder.isDownloading()) || (uploaderBinder != null && uploaderBinder.isUploading(user, file))) { setButtonsForTransferring(); @@ -662,7 +662,7 @@ private void setButtonsForTransferring() { FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); //if (getFile().isDownloading()) { - if (downloaderBinder != null && downloaderBinder.isDownloading(user, getFile())) { + if (downloaderBinder != null && downloaderBinder.isDownloading()) { binding.progressText.setText(R.string.downloader_download_in_progress_ticker); } else { if (uploaderBinder != null && uploaderBinder.isUploading(user, getFile())) { diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 08e7416512bf..f6876116a1d2 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -998,8 +998,8 @@ public void cancelTransference(OCFile file) { // for both files and folders FileDownloadWorker.FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder(); - if (downloaderBinder != null && downloaderBinder.isDownloading(currentUser, file)) { - downloaderBinder.cancelPendingOrCurrentDownloads(currentUser.toPlatformAccount(), file); + if (downloaderBinder != null && downloaderBinder.isDownloading()) { + downloaderBinder.cancelPendingOrCurrentDownloads(); } FileUploaderBinder uploaderBinder = fileActivity.getFileUploaderBinder(); if (uploaderBinder != null && uploaderBinder.isUploading(currentUser, file)) { diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 13363d231fd2..9bba853ff241 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -411,7 +411,7 @@ public void requestForDownload(OCFile file, String downloadBehaviour) { if (mDownloaderBinder == null) { Log_OC.d(TAG, "requestForDownload called without binder to download service"); - } else if (!mDownloaderBinder.isDownloading(getUserAccountManager().getUser(), file)) { + } else if (!mDownloaderBinder.isDownloading()) { final User user = getUser().orElseThrow(RuntimeException::new); new FileDownloadHelper().downloadFile(user, file, downloadBehaviour); } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index d4a1bd18c154..8c2c5d02b54a 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -478,7 +478,7 @@ public void onFileActionChosen(final int itemId) { getView(), backgroundJobManager); } else if (itemId == R.id.action_download_file) { - if (!containerActivity.getFileDownloaderBinder().isDownloading(user, getFile())) { + if (!containerActivity.getFileDownloaderBinder().isDownloading()) { new FileDownloadHelper().downloadFile(user, getFile()); } } From e3d8e853376ef12f64948bfd93b036538b00a70f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 28 Dec 2023 09:54:03 +0100 Subject: [PATCH 034/189] Fix FileDownloaderBinder cancelAllDownloadsForAccount Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadWorker.kt | 11 ++++++----- .../android/operations/DownloadFileOperation.java | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 26fb514d5569..94824ee90a0a 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -155,8 +155,8 @@ class FileDownloadWorker( downloadType ) - operation.addDatatransferProgressListener(this) - operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder) + operation.addDownloadDataTransferProgressListener(this) + operation.addDownloadDataTransferProgressListener(downloadBinder as FileDownloaderBinder) val putResult = pendingDownloads.putIfAbsent( user?.accountName, file.remotePath, @@ -203,7 +203,7 @@ class FileDownloadWorker( val isAccountExist = accountManager.exists(currentDownload?.user?.toPlatformAccount()) if (!isAccountExist) { - cancelPendingDownloads(currentDownload?.user?.accountName) + removePendingDownload(currentDownload?.user?.accountName) return } @@ -228,7 +228,7 @@ class FileDownloadWorker( } } - private fun cancelPendingDownloads(accountName: String?) { + private fun removePendingDownload(accountName: String?) { pendingDownloads.remove(accountName) } @@ -358,10 +358,11 @@ class FileDownloadWorker( fun cancelAllDownloadsForAccount(accountName: String?) { if (currentDownload?.user?.nameEquals(accountName) == true) { + context.cancelWork(JOB_FILES_DOWNLOAD) currentDownload?.cancel() } - cancelPendingDownloads(accountName) + removePendingDownload(accountName) } fun isDownloading(): Boolean { diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index 9da4a78e2033..568467654fcf 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -260,7 +260,7 @@ public void cancel() { } - public void addDatatransferProgressListener (OnDatatransferProgressListener listener) { + public void addDownloadDataTransferProgressListener(OnDatatransferProgressListener listener) { synchronized (dataTransferListeners) { dataTransferListeners.add(listener); } From 3b5b4313eb94ab68b33c7fad8c0794ca96b93b4c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 28 Dec 2023 10:20:56 +0100 Subject: [PATCH 035/189] Use BackgroundJobManager for cancel Downloads Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadWorker.kt | 11 ++++++----- .../com/nextcloud/client/jobs/BackgroundJobManager.kt | 2 ++ .../nextcloud/client/jobs/BackgroundJobManagerImpl.kt | 4 ++++ .../nextcloud/utils/extensions/ContextExtensions.kt | 4 ---- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 94824ee90a0a..46b5e22c8365 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -37,7 +37,6 @@ import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.jobs.BackgroundJobManagerImpl.Companion.JOB_FILES_DOWNLOAD import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional -import com.nextcloud.utils.extensions.cancelWork import com.nextcloud.utils.extensions.isWorkScheduled import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -353,13 +352,15 @@ class FileDownloadWorker( private val boundListeners: MutableMap = HashMap() fun cancelPendingOrCurrentDownloads() { - context.cancelWork(JOB_FILES_DOWNLOAD) + helper.backgroundJobManager.cancelFilesDownloadJob(currentUser.get()) } fun cancelAllDownloadsForAccount(accountName: String?) { - if (currentDownload?.user?.nameEquals(accountName) == true) { - context.cancelWork(JOB_FILES_DOWNLOAD) - currentDownload?.cancel() + currentDownload?.user?.let { + if (it.nameEquals(accountName)) { + helper.backgroundJobManager.cancelFilesDownloadJob(it) + currentDownload?.cancel() + } } removePendingDownload(accountName) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 4b2f505c8d3f..7223ab067c2b 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -146,6 +146,8 @@ interface BackgroundJobManager { fun getFileUploads(user: User): LiveData> fun cancelFilesUploadJob(user: User) + fun cancelFilesDownloadJob(user: User) + @Suppress("LongParameterList") fun startFilesDownloadJob( user: User, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 9ce6b3a85d63..ff2a7fa8941e 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -609,6 +609,10 @@ internal class BackgroundJobManagerImpl( workManager.cancelJob(JOB_FILES_UPLOAD, user) } + override fun cancelFilesDownloadJob(user: User) { + workManager.cancelJob(JOB_FILES_DOWNLOAD, user) + } + override fun startPdfGenerateAndUploadWork( user: User, uploadFolder: String, diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt index 35527d4af8b1..613599ae06e3 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt @@ -64,7 +64,3 @@ fun Context.isWorkScheduled(tag: String): Boolean { return running } - -fun Context.cancelWork(tag: String) { - WorkManager.getInstance(this).cancelAllWorkByTag(tag) -} From 4e4c3a6dd514190e957ee8e4336c0a29bd0b37f1 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 09:05:33 +0100 Subject: [PATCH 036/189] Rebase master Signed-off-by: alperozturk --- .../android/files/FileMenuFilterIT.kt | 2 +- .../files/downloader/FileDownloadWorker.kt | 10 ++-- .../client/jobs/BackgroundJobManager.kt | 2 + .../client/jobs/BackgroundJobManagerImpl.kt | 12 ++++- .../utils/extensions/ContextExtensions.kt | 24 +-------- .../utils/extensions/WorkManagerExtensions.kt | 49 +++++++++++++++++++ .../android/files/FileMenuFilter.java | 3 +- .../ui/activity/FileDisplayActivity.java | 4 +- .../android/ui/adapter/OCFileListDelegate.kt | 2 +- .../ui/fragment/FileDetailFragment.java | 5 +- .../ui/helpers/FileOperationsHelper.java | 2 +- .../ui/preview/PreviewImageActivity.java | 6 +-- .../ui/preview/PreviewMediaFragment.java | 2 +- 13 files changed, 82 insertions(+), 41 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/utils/extensions/WorkManagerExtensions.kt diff --git a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt index 0b7f37bdcee1..5e48d0b9647d 100644 --- a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt @@ -77,7 +77,7 @@ class FileMenuFilterIT : AbstractIT() { MockKAnnotations.init(this) every { mockFileUploaderBinder.isUploading(any(), any()) } returns false every { mockComponentsGetter.fileUploaderBinder } returns mockFileUploaderBinder - every { mockFileDownloaderBinder.isDownloading() } returns false + every { mockFileDownloaderBinder.isDownloading(any(), any()) } returns false every { mockComponentsGetter.fileDownloaderBinder } returns mockFileDownloaderBinder every { mockOperationsServiceBinder.isSynchronizing(any(), any()) } returns false every { mockComponentsGetter.operationsServiceBinder } returns mockOperationsServiceBinder diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 46b5e22c8365..84d6bfaa24e5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -34,10 +34,8 @@ import androidx.work.WorkerParameters import com.google.gson.Gson import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager -import com.nextcloud.client.jobs.BackgroundJobManagerImpl.Companion.JOB_FILES_DOWNLOAD import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional -import com.nextcloud.utils.extensions.isWorkScheduled import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager @@ -122,6 +120,7 @@ class FileDownloadWorker( } } + // FIXME not returning multiple string for folder private fun getRequestDownloads(): AbstractList { conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) @@ -366,8 +365,11 @@ class FileDownloadWorker( removePendingDownload(accountName) } - fun isDownloading(): Boolean { - return context.isWorkScheduled(JOB_FILES_DOWNLOAD) + fun isDownloading(user: User?, file: OCFile?): Boolean { + return user != null && file != null && helper.backgroundJobManager.isStartFileDownloadJobScheduled( + user, + file + ) } fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 7223ab067c2b..1f3bc87057a8 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -148,6 +148,8 @@ interface BackgroundJobManager { fun cancelFilesDownloadJob(user: User) + fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean + @Suppress("LongParameterList") fun startFilesDownloadJob( user: User, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index ff2a7fa8941e..491f03dfc690 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -41,6 +41,7 @@ import com.nextcloud.client.di.Injectable 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.OCFile import com.owncloud.android.lib.common.operations.OperationCancelledException import com.owncloud.android.operations.DownloadType @@ -538,6 +539,14 @@ internal class BackgroundJobManagerImpl( .build() } + private fun startFileDownloadJobTag(user: User, file: OCFile): String { + return JOB_FILES_DOWNLOAD + user.accountName + file.fileId + } + + override fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean { + return workManager.isWorkScheduled(startFileDownloadJobTag(user, file)) + } + @Throws(OperationCancelledException::class) override fun startFilesDownloadJob( user: User, @@ -597,7 +606,8 @@ internal class BackgroundJobManagerImpl( conflictUploadId ) - workManager.enqueueUniqueWork(JOB_FILES_DOWNLOAD + user.accountName, ExistingWorkPolicy.REPLACE, request) + val tag = startFileDownloadJobTag(user, ocFile) + workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) } override fun getFileUploads(user: User): LiveData> { diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt index 613599ae06e3..ee0b30e2ad0e 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt @@ -27,12 +27,8 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.Build -import androidx.work.WorkInfo import androidx.work.WorkManager -import com.google.common.util.concurrent.ListenableFuture import com.owncloud.android.datamodel.ReceiverFlag -import com.owncloud.android.lib.common.utils.Log_OC -import java.util.concurrent.ExecutionException @SuppressLint("UnspecifiedRegisterReceiverFlag") fun Context.registerBroadcastReceiver(receiver: BroadcastReceiver?, filter: IntentFilter, flag: ReceiverFlag): Intent? { @@ -44,23 +40,5 @@ fun Context.registerBroadcastReceiver(receiver: BroadcastReceiver?, filter: Inte } fun Context.isWorkScheduled(tag: String): Boolean { - val instance = WorkManager.getInstance(this) - val statuses: ListenableFuture> = instance.getWorkInfosByTag(tag) - var running = false - var workInfoList: List = emptyList() - - try { - workInfoList = statuses.get() - } catch (e: ExecutionException) { - Log_OC.d("Worker", "ExecutionException in isWorkScheduled: $e") - } catch (e: InterruptedException) { - Log_OC.d("Worker", "InterruptedException in isWorkScheduled: $e") - } - - for (workInfo in workInfoList) { - val state = workInfo.state - running = running || (state == WorkInfo.State.RUNNING || state == WorkInfo.State.ENQUEUED) - } - - return running + return WorkManager.getInstance(this).isWorkScheduled(tag) } diff --git a/app/src/main/java/com/nextcloud/utils/extensions/WorkManagerExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/WorkManagerExtensions.kt new file mode 100644 index 000000000000..35fda9b10f6d --- /dev/null +++ b/app/src/main/java/com/nextcloud/utils/extensions/WorkManagerExtensions.kt @@ -0,0 +1,49 @@ +/* + * 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 . + */ + +package com.nextcloud.utils.extensions + +import androidx.work.WorkInfo +import androidx.work.WorkManager +import com.google.common.util.concurrent.ListenableFuture +import com.owncloud.android.lib.common.utils.Log_OC +import java.util.concurrent.ExecutionException + +fun WorkManager.isWorkScheduled(tag: String): Boolean { + val statuses: ListenableFuture> = this.getWorkInfosByTag(tag) + var running = false + var workInfoList: List = emptyList() + + try { + workInfoList = statuses.get() + } catch (e: ExecutionException) { + Log_OC.d("Worker", "ExecutionException in isWorkScheduled: $e") + } catch (e: InterruptedException) { + Log_OC.d("Worker", "InterruptedException in isWorkScheduled: $e") + } + + for (workInfo in workInfoList) { + val state = workInfo.state + running = running || (state == WorkInfo.State.RUNNING || state == WorkInfo.State.ENQUEUED) + } + + return running +} diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index b5e721e4a99f..83c1db654425 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -400,9 +400,10 @@ private boolean anyFileSynchronizing(OperationsServiceBinder opsBinder) { private boolean anyFileDownloading(FileDownloadWorker.FileDownloaderBinder downloaderBinder) { boolean downloading = false; + if (downloaderBinder != null) { for (Iterator iterator = files.iterator(); !downloading && iterator.hasNext(); ) { - downloading = downloaderBinder.isDownloading(); + downloading = downloaderBinder.isDownloading(user, iterator.next()); } } return downloading; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 5be55acdd3fb..3f42beeca9dc 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1884,7 +1884,7 @@ public void onTransferStateChanged(OCFile file, boolean downloading, boolean upl private void requestForDownload() { User user = getUser().orElseThrow(RuntimeException::new); - if (!mDownloaderBinder.isDownloading()) { + if (!mDownloaderBinder.isDownloading(user, mWaitingToPreview)) { new FileDownloadHelper().downloadFile(user, mWaitingToPreview); } } @@ -1956,7 +1956,7 @@ public void run() { private void requestForDownload(OCFile file, String downloadBehaviour, String packageName, String activityName) { final User currentUser = getUser().orElseThrow(RuntimeException::new); - if (!mDownloaderBinder.isDownloading()) { + if (!mDownloaderBinder.isDownloading(currentUser, file)) { new FileDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 4be366f9afd8..e350d8b7c856 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -344,7 +344,7 @@ class OCFileListDelegate( val fileUploaderBinder = transferServiceGetter.fileUploaderBinder when { operationsServiceBinder?.isSynchronizing(user, file) == true || - fileDownloaderBinder?.isDownloading() == true || + fileDownloaderBinder?.isDownloading(user, file) == true || fileUploaderBinder?.isUploading(user, file) == true -> { // synchronizing, downloading or uploading gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index a152511bb231..2091fa90fe44 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -537,7 +537,7 @@ public void updateFileDetails(boolean transferring, boolean refresh) { FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); if (transferring - || (downloaderBinder != null && downloaderBinder.isDownloading()) + || (downloaderBinder != null && downloaderBinder.isDownloading(user, file)) || (uploaderBinder != null && uploaderBinder.isUploading(user, file))) { setButtonsForTransferring(); @@ -661,8 +661,7 @@ private void setButtonsForTransferring() { binding.progressText.setVisibility(View.VISIBLE); FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); - //if (getFile().isDownloading()) { - if (downloaderBinder != null && downloaderBinder.isDownloading()) { + if (downloaderBinder != null && downloaderBinder.isDownloading(user, getFile())) { binding.progressText.setText(R.string.downloader_download_in_progress_ticker); } else { if (uploaderBinder != null && uploaderBinder.isUploading(user, getFile())) { diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index f6876116a1d2..80dd92aa1ca3 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -998,7 +998,7 @@ public void cancelTransference(OCFile file) { // for both files and folders FileDownloadWorker.FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder(); - if (downloaderBinder != null && downloaderBinder.isDownloading()) { + if (downloaderBinder != null && downloaderBinder.isDownloading(currentUser, file)) { downloaderBinder.cancelPendingOrCurrentDownloads(); } FileUploaderBinder uploaderBinder = fileActivity.getFileUploaderBinder(); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 9bba853ff241..352f4edf47fe 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -408,11 +408,11 @@ public void requestForDownload(OCFile file) { } public void requestForDownload(OCFile file, String downloadBehaviour) { + final User user = getUser().orElseThrow(RuntimeException::new); + if (mDownloaderBinder == null) { Log_OC.d(TAG, "requestForDownload called without binder to download service"); - - } else if (!mDownloaderBinder.isDownloading()) { - final User user = getUser().orElseThrow(RuntimeException::new); + } else if (!mDownloaderBinder.isDownloading(user, file)) { new FileDownloadHelper().downloadFile(user, file, downloadBehaviour); } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index 8c2c5d02b54a..d4a1bd18c154 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -478,7 +478,7 @@ public void onFileActionChosen(final int itemId) { getView(), backgroundJobManager); } else if (itemId == R.id.action_download_file) { - if (!containerActivity.getFileDownloaderBinder().isDownloading()) { + if (!containerActivity.getFileDownloaderBinder().isDownloading(user, getFile())) { new FileDownloadHelper().downloadFile(user, getFile()); } } From 875c509504ad85a441b4bc701c462c0dfc37d0ad Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 09:05:52 +0100 Subject: [PATCH 037/189] Rebase master Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 13 ------ .../files/downloader/FileDownloadWorker.kt | 2 + .../client/jobs/BackgroundJobManager.kt | 12 ------ .../client/jobs/BackgroundJobManagerImpl.kt | 42 ------------------- .../SynchronizeFolderOperation.java | 12 +++++- 5 files changed, 12 insertions(+), 69 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index ecbe944a9af3..35288eb166f2 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -80,19 +80,6 @@ class FileDownloadHelper { storageManager?.saveConflict(file, null) } - fun downloadFiles(user: User, ocFile: List, cancelRequest: AtomicBoolean) { - backgroundJobManager.startFilesDownloadJob( - user, - ocFile, - "", - DownloadType.DOWNLOAD, - "", - "", - null, - cancelRequest - ) - } - fun downloadFile(user: User, ocFile: OCFile) { backgroundJobManager.startFileDownloadJob( user, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 84d6bfaa24e5..336557ba98d2 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -34,8 +34,10 @@ import androidx.work.WorkerParameters import com.google.gson.Gson import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.jobs.BackgroundJobManagerImpl.Companion.JOB_FILES_DOWNLOAD import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional +import com.nextcloud.utils.extensions.isWorkScheduled import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 1f3bc87057a8..f7263265742f 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -150,18 +150,6 @@ interface BackgroundJobManager { fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean - @Suppress("LongParameterList") - fun startFilesDownloadJob( - user: User, - files: List, - behaviour: String, - downloadType: DownloadType?, - activityName: String, - packageName: String, - conflictUploadId: Long?, - cancelRequest: AtomicBoolean - ) - @Suppress("LongParameterList") fun startFileDownloadJob( user: User, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 491f03dfc690..79234a8ec81b 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -43,12 +43,10 @@ import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.utils.extensions.isWorkScheduled import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.lib.common.operations.OperationCancelledException import com.owncloud.android.operations.DownloadType import java.util.Date import java.util.UUID import java.util.concurrent.TimeUnit -import java.util.concurrent.atomic.AtomicBoolean import kotlin.reflect.KClass /** @@ -547,46 +545,6 @@ internal class BackgroundJobManagerImpl( return workManager.isWorkScheduled(startFileDownloadJobTag(user, file)) } - @Throws(OperationCancelledException::class) - override fun startFilesDownloadJob( - user: User, - files: List, - behaviour: String, - downloadType: DownloadType?, - activityName: String, - packageName: String, - conflictUploadId: Long?, - cancelRequest: AtomicBoolean - ) { - val workRequestList = mutableListOf() - - for (file in files) { - synchronized(cancelRequest) { - if (cancelRequest.get()) { - throw OperationCancelledException() - } - - workRequestList.add( - getOneTimeDownloadRequest( - user, - file, - behaviour, - downloadType, - activityName, - packageName, - conflictUploadId - ) - ) - } - } - - val chain = workManager - .beginWith(workRequestList.first()) - .then(workRequestList.subList(1, workRequestList.size)) - - chain.enqueue() - } - override fun startFileDownloadJob( user: User, ocFile: OCFile, diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index e69a96821b2f..0cb9cff609e8 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -444,9 +444,17 @@ private void syncContents() throws OperationCancelledException { startContentSynchronizations(mFilesToSyncContents); } - private void startDirectDownloads() { + private void startDirectDownloads() throws OperationCancelledException { FileDownloadHelper downloadHelper = new FileDownloadHelper(); - downloadHelper.downloadFiles(user, mFilesForDirectDownload, mCancellationRequested); + + for (OCFile file : mFilesForDirectDownload) { + synchronized(mCancellationRequested) { + if (mCancellationRequested.get()) { + throw new OperationCancelledException(); + } + downloadHelper.downloadFile(user, file); + } + } } /** From f756a03147f105d693eec58478dd25fe5b754fb8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 28 Dec 2023 15:20:57 +0100 Subject: [PATCH 038/189] Fix requestDownloads Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadWorker.kt | 10 ++++------ .../android/ui/activity/FileDisplayActivity.java | 5 +++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 336557ba98d2..0fa8963261a9 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -34,10 +34,8 @@ import androidx.work.WorkerParameters import com.google.gson.Gson import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager -import com.nextcloud.client.jobs.BackgroundJobManagerImpl.Companion.JOB_FILES_DOWNLOAD import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional -import com.nextcloud.utils.extensions.isWorkScheduled import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager @@ -122,7 +120,6 @@ class FileDownloadWorker( } } - // FIXME not returning multiple string for folder private fun getRequestDownloads(): AbstractList { conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) @@ -144,7 +141,7 @@ class FileDownloadWorker( val requestedDownloads: AbstractList = Vector() - try { + return try { val operation = DownloadFileOperation( user, file, @@ -168,11 +165,12 @@ class FileDownloadWorker( requestedDownloads.add(downloadKey) localBroadcastManager.sendBroadcast(intents.newDownloadIntent(operation, putResult.second)) } + + requestedDownloads } catch (e: IllegalArgumentException) { Log_OC.e(TAG, "Not enough information provided in intent: " + e.message) + requestedDownloads } - - return requestedDownloads } private fun addAccountUpdateListener() { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 3f42beeca9dc..dfdc51293033 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1587,6 +1587,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { } else { return; } + // a new chance to get the mDownloadBinder through // getFileDownloadBinder() - THIS IS A MESS OCFileListFragment listOfFiles = getListOfFilesFragment(); @@ -1594,9 +1595,9 @@ public void onServiceConnected(ComponentName component, IBinder service) { IntentExtensionsKt.getParcelableArgument(getIntent(), EXTRA_FILE, OCFile.class) == null))) { listOfFiles.listDirectory(MainApp.isOnlyOnDevice(), false); } + Fragment leftFragment = getLeftFragment(); - if (leftFragment instanceof FileDetailFragment) { - FileDetailFragment detailFragment = (FileDetailFragment) leftFragment; + if (leftFragment instanceof FileDetailFragment detailFragment) { detailFragment.listenForTransferProgress(); detailFragment.updateFileDetails(false, false); } From 2b6f96d1e38800fb219957e233766b09b1244f59 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 28 Dec 2023 15:55:33 +0100 Subject: [PATCH 039/189] Fix kotlin spotless check Signed-off-by: alperozturk --- .../com/nextcloud/client/files/downloader/FileDownloadHelper.kt | 1 - .../main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 35288eb166f2..cb53a4db9f4d 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -31,7 +31,6 @@ import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType import com.owncloud.android.utils.MimeTypeUtil import java.io.File -import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject class FileDownloadHelper { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index f7263265742f..f3488a222f94 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -24,7 +24,6 @@ import androidx.work.ListenableWorker import com.nextcloud.client.account.User import com.owncloud.android.datamodel.OCFile import com.owncloud.android.operations.DownloadType -import java.util.concurrent.atomic.AtomicBoolean /** * This interface allows to control, schedule and monitor all application From d166035dda7f3933e2bf4a888e62ed5e9843f40a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 10:00:40 +0100 Subject: [PATCH 040/189] Fix isDownloading, cancel, success notification Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 19 ++++++++++++ .../files/downloader/FileDownloadWorker.kt | 9 ++++-- .../client/jobs/BackgroundJobManager.kt | 2 +- .../client/jobs/BackgroundJobManagerImpl.kt | 4 +-- .../download/DownloadNotificationManager.kt | 2 +- .../android/files/FileMenuFilter.java | 18 +++++------ .../android/ui/activity/FileActivity.java | 1 + .../ui/activity/FileDisplayActivity.java | 9 +++--- .../android/ui/adapter/OCFileListDelegate.kt | 5 ++-- .../ui/fragment/FileDetailFragment.java | 11 +++---- .../ui/helpers/FileOperationsHelper.java | 1 + .../ui/preview/PreviewImageActivity.java | 6 ++-- .../ui/preview/PreviewMediaActivity.kt | 30 +++++++++---------- .../ui/preview/PreviewMediaFragment.java | 5 ++-- 14 files changed, 75 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index cb53a4db9f4d..c9c17bf6dca5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -45,6 +45,13 @@ class FileDownloadHelper { MainApp.getAppComponent().inject(this) } + fun isDownloading(user: User?, file: OCFile?): Boolean { + return user != null && file != null && backgroundJobManager.isStartFileDownloadJobScheduled( + user, + file + ) + } + fun saveFile( file: OCFile, currentDownload: DownloadFileOperation?, @@ -103,6 +110,18 @@ class FileDownloadHelper { ) } + fun downloadFile(user: User, ocFile: OCFile, behaviour: String, packageName: String, activityName: String) { + backgroundJobManager.startFileDownloadJob( + user, + ocFile, + behaviour, + DownloadType.DOWNLOAD, + packageName, + packageName, + null + ) + } + fun downloadFile(user: User, ocFile: OCFile, downloadType: DownloadType) { backgroundJobManager.startFileDownloadJob( user, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 0fa8963261a9..e8b1e1104580 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -351,13 +351,18 @@ class FileDownloadWorker( private val boundListeners: MutableMap = HashMap() fun cancelPendingOrCurrentDownloads() { - helper.backgroundJobManager.cancelFilesDownloadJob(currentUser.get()) + currentDownload?.file?.let { file -> + helper.backgroundJobManager.cancelFilesDownloadJob(currentUser.get(), file) + } } fun cancelAllDownloadsForAccount(accountName: String?) { currentDownload?.user?.let { if (it.nameEquals(accountName)) { - helper.backgroundJobManager.cancelFilesDownloadJob(it) + currentDownload?.file?.let { file -> + helper.backgroundJobManager.cancelFilesDownloadJob(it, file) + } + currentDownload?.cancel() } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index f3488a222f94..ee338476397f 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -145,7 +145,7 @@ interface BackgroundJobManager { fun getFileUploads(user: User): LiveData> fun cancelFilesUploadJob(user: User) - fun cancelFilesDownloadJob(user: User) + fun cancelFilesDownloadJob(user: User, file: OCFile) fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 79234a8ec81b..11a2ab765a25 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -577,8 +577,8 @@ internal class BackgroundJobManagerImpl( workManager.cancelJob(JOB_FILES_UPLOAD, user) } - override fun cancelFilesDownloadJob(user: User) { - workManager.cancelJob(JOB_FILES_DOWNLOAD, user) + override fun cancelFilesDownloadJob(user: User, file: OCFile) { + workManager.cancelAllWorkByTag(startFileDownloadJobTag(user, file)) } override fun startPdfGenerateAndUploadWork( diff --git a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt index 51bace7e6728..f15896692b6d 100644 --- a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt @@ -89,7 +89,7 @@ class DownloadNotificationManager(private val context: Context, private val view val notifyId = SecureRandom().nextInt() val contentText = if (result.isSuccess) { - context.getString(R.string.downloader_download_succeeded_ticker) + download.file.fileName + " " + context.getString(R.string.downloader_download_succeeded_ticker) } else { ErrorMessageAdapter.getErrorCauseMessage( result, diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index 83c1db654425..22b942e01003 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -31,6 +31,7 @@ import com.nextcloud.android.files.FileLockingHelper; import com.nextcloud.client.account.User; import com.nextcloud.client.editimage.EditImageActivity; +import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.utils.EditorUtils; import com.owncloud.android.R; @@ -380,9 +381,9 @@ private boolean anyFileSynchronizing() { if (componentsGetter != null && !files.isEmpty() && user != null) { OperationsServiceBinder opsBinder = componentsGetter.getOperationsServiceBinder(); FileUploaderBinder uploaderBinder = componentsGetter.getFileUploaderBinder(); - FileDownloadWorker.FileDownloaderBinder downloaderBinder = componentsGetter.getFileDownloaderBinder(); + FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); synchronizing = anyFileSynchronizing(opsBinder) || // comparing local and remote - anyFileDownloading(downloaderBinder) || + anyFileDownloading(fileDownloadHelper) || anyFileUploading(uploaderBinder); } return synchronizing; @@ -398,15 +399,14 @@ private boolean anyFileSynchronizing(OperationsServiceBinder opsBinder) { return synchronizing; } - private boolean anyFileDownloading(FileDownloadWorker.FileDownloaderBinder downloaderBinder) { - boolean downloading = false; - - if (downloaderBinder != null) { - for (Iterator iterator = files.iterator(); !downloading && iterator.hasNext(); ) { - downloading = downloaderBinder.isDownloading(user, iterator.next()); + private boolean anyFileDownloading(FileDownloadHelper downloadHelper) { + for (OCFile file : files) { + if (downloadHelper.isDownloading(user, file)) { + return true; } } - return downloading; + + return false; } private boolean anyFileUploading(FileUploaderBinder uploaderBinder) { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index f0c1573cc293..11910ca5cd93 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -166,6 +166,7 @@ public abstract class FileActivity extends DrawerActivity private boolean mResumed; + protected FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); protected FileDownloadWorker.FileDownloaderBinder mDownloaderBinder; protected FileUploaderBinder mUploaderBinder; private ServiceConnection mUploadServiceConnection; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index dfdc51293033..495b54d19262 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1564,6 +1564,7 @@ protected ServiceConnection newTransferenceServiceConnection() { return new ListServiceConnection(); } + // FIXME ServiceConnection will not trigger anymore /** * Defines callbacks for service binding, passed to bindService() */ @@ -1885,8 +1886,8 @@ public void onTransferStateChanged(OCFile file, boolean downloading, boolean upl private void requestForDownload() { User user = getUser().orElseThrow(RuntimeException::new); - if (!mDownloaderBinder.isDownloading(user, mWaitingToPreview)) { - new FileDownloadHelper().downloadFile(user, mWaitingToPreview); + if (!fileDownloadHelper.isDownloading(user, mWaitingToPreview)) { + fileDownloadHelper.downloadFile(user, mWaitingToPreview); } } @@ -1957,8 +1958,8 @@ public void run() { private void requestForDownload(OCFile file, String downloadBehaviour, String packageName, String activityName) { final User currentUser = getUser().orElseThrow(RuntimeException::new); - if (!mDownloaderBinder.isDownloading(currentUser, file)) { - new FileDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); + if (!fileDownloadHelper.isDownloading(currentUser, file)) { + fileDownloadHelper.downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index e350d8b7c856..5cd63ffe60c8 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -32,6 +32,7 @@ import androidx.core.content.res.ResourcesCompat import com.elyeproj.loaderviewlibrary.LoaderImageView 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.utils.extensions.createRoundedOutline import com.owncloud.android.R @@ -340,11 +341,11 @@ class OCFileListDelegate( private fun showLocalFileIndicator(file: OCFile, gridViewHolder: ListGridImageViewHolder) { val operationsServiceBinder = transferServiceGetter.operationsServiceBinder - val fileDownloaderBinder = transferServiceGetter.fileDownloaderBinder + val fileDownloadHelper = FileDownloadHelper() val fileUploaderBinder = transferServiceGetter.fileUploaderBinder when { operationsServiceBinder?.isSynchronizing(user, file) == true || - fileDownloaderBinder?.isDownloading(user, file) == true || + fileDownloadHelper.isDownloading(user, file) || fileUploaderBinder?.isUploading(user, file) == true -> { // synchronizing, downloading or uploading gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 2091fa90fe44..55c9f6700798 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -44,6 +44,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; +import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ClientFactory; @@ -502,7 +503,7 @@ public void updateFileDetails(OCFile file, User user) { * TODO Remove parameter when the transferring state of files is kept in database. * * @param transferring Flag signaling if the file should be considered as downloading or uploading, although - * {@link com.nextcloud.client.files.downloader.FileDownloadWorker.FileDownloaderBinder#isDownloading(User, OCFile)} and + * {@link FileDownloadHelper#isDownloading(User, OCFile)} and * {@link FileUploaderBinder#isUploading(User, OCFile)} return false. * @param refresh If 'true', try to refresh the whole file from the database */ @@ -534,10 +535,10 @@ public void updateFileDetails(boolean transferring, boolean refresh) { setFavoriteIconStatus(file.isFavorite()); // configure UI for depending upon local state of the file - FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); + FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); if (transferring - || (downloaderBinder != null && downloaderBinder.isDownloading(user, file)) + || (fileDownloadHelper.isDownloading(user, file)) || (uploaderBinder != null && uploaderBinder.isUploading(user, file))) { setButtonsForTransferring(); @@ -659,9 +660,9 @@ private void setButtonsForTransferring() { // show the progress bar for the transfer binding.progressBlock.setVisibility(View.VISIBLE); binding.progressText.setVisibility(View.VISIBLE); - FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); + FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); - if (downloaderBinder != null && downloaderBinder.isDownloading(user, getFile())) { + if (fileDownloadHelper.isDownloading(user, getFile())) { binding.progressText.setText(R.string.downloader_download_in_progress_ticker); } else { if (uploaderBinder != null && uploaderBinder.isUploading(user, getFile())) { diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 80dd92aa1ca3..d6cb6f325597 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -47,6 +47,7 @@ import com.nextcloud.client.account.CurrentAccountProvider; import com.nextcloud.client.account.User; +import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ConnectivityService; diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 352f4edf47fe..aacea713eb58 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -410,10 +410,8 @@ public void requestForDownload(OCFile file) { public void requestForDownload(OCFile file, String downloadBehaviour) { final User user = getUser().orElseThrow(RuntimeException::new); - if (mDownloaderBinder == null) { - Log_OC.d(TAG, "requestForDownload called without binder to download service"); - } else if (!mDownloaderBinder.isDownloading(user, file)) { - new FileDownloadHelper().downloadFile(user, file, downloadBehaviour); + if (!fileDownloadHelper.isDownloading(user, file)) { + fileDownloadHelper.downloadFile(user, file, downloadBehaviour); } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt index f9969d283578..8de694773eed 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt @@ -65,6 +65,8 @@ import androidx.media3.ui.PlayerView import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.di.Injectable +import com.nextcloud.client.files.downloader.FileDownloadHelper +import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.client.jobs.BackgroundJobManager import com.nextcloud.client.media.ExoplayerListener import com.nextcloud.client.media.NextcloudExoPlayer.createNextcloudExoplayer @@ -80,8 +82,6 @@ import com.owncloud.android.databinding.ActivityPreviewMediaBinding import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.ThumbnailsCacheManager import com.owncloud.android.files.StreamMediaFileOperation -import com.owncloud.android.files.services.FileDownloader -import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.operations.OnRemoteOperationListener import com.owncloud.android.lib.common.operations.RemoteOperation @@ -576,14 +576,14 @@ class PreviewMediaActivity : private inner class PreviewMediaServiceConnection : ServiceConnection { override fun onServiceConnected(componentName: ComponentName?, service: IBinder?) { componentName?.let { - if (it == ComponentName(this@PreviewMediaActivity, FileDownloader::class.java)) { - mDownloaderBinder = service as FileDownloaderBinder + if (it == ComponentName(this@PreviewMediaActivity, FileDownloadWorker::class.java)) { + mDownloaderBinder = service as FileDownloadWorker.FileDownloaderBinder } } } override fun onServiceDisconnected(componentName: ComponentName?) { - if (componentName == ComponentName(this@PreviewMediaActivity, FileDownloader::class.java)) { + if (componentName == ComponentName(this@PreviewMediaActivity, FileDownloadWorker::class.java)) { Log_OC.d(PreviewImageActivity.TAG, "Download service suddenly disconnected") mDownloaderBinder = null } @@ -600,21 +600,21 @@ class PreviewMediaActivity : packageName: String? = null, activityName: String? = null ) { - if (fileDownloaderBinder.isDownloading(user, file)) { + if (fileDownloadHelper.isDownloading(user, file)) { return } - val intent = Intent(this, FileDownloader::class.java).apply { - putExtra(FileDownloader.EXTRA_USER, user) - putExtra(FileDownloader.EXTRA_FILE, file) - downloadBehavior?.let { behavior -> - putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, behavior) + user?.let { user -> + file?.let { file -> + fileDownloadHelper.downloadFile( + user, + file, + downloadBehavior ?: "", + packageName ?: "", + activityName ?: "" + ) } - putExtra(SendShareDialog.PACKAGE_NAME, packageName) - putExtra(SendShareDialog.ACTIVITY_NAME, activityName) } - - startService(intent) } private fun seeDetails() { diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index d4a1bd18c154..28c3e4d4f314 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -131,6 +131,7 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene private boolean autoplay; private boolean isLivePhoto; + private final FileDownloadHelper downloadHelper = new FileDownloadHelper(); private boolean prepared; private PlayerServiceConnection mediaPlayerServiceConnection; @@ -478,8 +479,8 @@ public void onFileActionChosen(final int itemId) { getView(), backgroundJobManager); } else if (itemId == R.id.action_download_file) { - if (!containerActivity.getFileDownloaderBinder().isDownloading(user, getFile())) { - new FileDownloadHelper().downloadFile(user, getFile()); + if (!downloadHelper.isDownloading(user, getFile())) { + downloadHelper.downloadFile(user, getFile()); } } } From ce463aff0bb43d7c25db0df00c0d5547d294ebb1 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 10:20:12 +0100 Subject: [PATCH 041/189] Implement WorkerState for replacing ServiceConnection Signed-off-by: alperozturk --- .../files/downloader/FileDownloadWorker.kt | 7 ++++ .../java/com/nextcloud/model/WorkerState.kt | 30 +++++++++++++ .../nextcloud/model/WorkerStateLiveData.kt | 42 +++++++++++++++++++ .../ui/activity/FileDisplayActivity.java | 34 ++++++++++----- 4 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/model/WorkerState.kt create mode 100644 app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index e8b1e1104580..c0fb808a22bc 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -36,6 +36,8 @@ import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional +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 @@ -138,6 +140,7 @@ class FileDownloadWorker( val behaviour = inputData.keyValueMap[BEHAVIOUR] as String val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String val packageName = inputData.keyValueMap[PACKAGE_NAME] as String + setWorkerState(user, file) val requestedDownloads: AbstractList = Vector() @@ -173,6 +176,10 @@ class FileDownloadWorker( } } + private fun setWorkerState(user: User, file: OCFile) { + WorkerStateLiveData.instance?.setWorkState(WorkerState.Download(user, file)) + } + private fun addAccountUpdateListener() { val am = AccountManager.get(context) am.addOnAccountsUpdatedListener(this, null, false) diff --git a/app/src/main/java/com/nextcloud/model/WorkerState.kt b/app/src/main/java/com/nextcloud/model/WorkerState.kt new file mode 100644 index 000000000000..1bf8a78f2847 --- /dev/null +++ b/app/src/main/java/com/nextcloud/model/WorkerState.kt @@ -0,0 +1,30 @@ +/* + * 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 . + */ + +package com.nextcloud.model + +import com.nextcloud.client.account.User +import com.owncloud.android.datamodel.OCFile + +sealed class WorkerState { + object Idle + class Download(var user: User, var file: OCFile): WorkerState() +} diff --git a/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt b/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt new file mode 100644 index 000000000000..8863b6dddac2 --- /dev/null +++ b/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt @@ -0,0 +1,42 @@ +/* + * 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 . + */ + +package com.nextcloud.model + +import androidx.lifecycle.LiveData + +class WorkerStateLiveData private constructor() : LiveData() { + + fun setWorkState(state: WorkerState) { + postValue(state) + } + + companion object { + var instance: WorkerStateLiveData? = null + get() { + if (field == null) { + field = WorkerStateLiveData() + } + return field + } + private set + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 495b54d19262..6635bf855926 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -73,6 +73,8 @@ import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.client.utils.IntentUtil; import com.nextcloud.java.util.Optional; +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; @@ -160,6 +162,7 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; +import androidx.lifecycle.Observer; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import kotlin.Unit; @@ -285,6 +288,7 @@ protected void onCreate(Bundle savedInstanceState) { checkStoragePath(); initSyncBroadcastReceiver(); + observeWorkerState(); } @SuppressWarnings("unchecked") @@ -1559,6 +1563,24 @@ public boolean isDrawerIndicatorAvailable() { return isRoot(getCurrentDir()); } + private void observeWorkerState() { + WorkerStateLiveData.Companion.getInstance().observe(this, state -> { + if (state instanceof WorkerState.Download) { + Log_OC.d(TAG, "Download worker started"); + handleDownloadWorkerState(); + } + }); + } + + private void handleDownloadWorkerState() { + if (mWaitingToPreview != null && getStorageManager() != null) { + mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); + if (mWaitingToPreview != null && !mWaitingToPreview.isDown()) { + requestForDownload(); + } + } + } + @Override protected ServiceConnection newTransferenceServiceConnection() { return new ListServiceConnection(); @@ -1572,17 +1594,7 @@ private class ListServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { - if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloadWorker.class))) { - Log_OC.d(TAG, "Download service connected"); - mDownloaderBinder = (FileDownloadWorker.FileDownloaderBinder) service; - if (mWaitingToPreview != null && getStorageManager() != null) { - // update the file - mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); - if (mWaitingToPreview != null && !mWaitingToPreview.isDown()) { - requestForDownload(); - } - } - } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { + if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service connected"); mUploaderBinder = (FileUploaderBinder) service; } else { From 14cb1d436bb315bd3f02379a417e69c6e711bc52 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 10:58:40 +0100 Subject: [PATCH 042/189] Use WorkerState for handling download state Signed-off-by: alperozturk --- .../android/files/FileMenuFilterIT.kt | 6 +- .../java/com/nextcloud/test/TestActivity.kt | 2 +- .../files/downloader/FileDownloadHelper.kt | 61 ++++++++++++++++++- .../files/downloader/FileDownloadWorker.kt | 49 ++++++--------- .../download/DownloadNotificationManager.kt | 2 +- .../java/com/nextcloud/model/WorkerState.kt | 6 +- .../android/files/FileMenuFilter.java | 1 - .../android/ui/activity/ComponentsGetter.java | 4 +- .../android/ui/activity/FileActivity.java | 6 +- .../ui/activity/FileDisplayActivity.java | 4 +- .../ui/activity/ManageAccountsActivity.java | 39 +++++++----- .../ui/fragment/FileDetailFragment.java | 9 ++- .../ui/helpers/FileOperationsHelper.java | 7 +-- .../ui/preview/FileDownloadFragment.java | 8 +-- .../ui/preview/PreviewImageActivity.java | 43 +++++++------ .../ui/preview/PreviewImagePagerAdapter.java | 1 - .../ui/preview/PreviewMediaActivity.kt | 26 -------- 17 files changed, 151 insertions(+), 123 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt index 5e48d0b9647d..9c19ce243f66 100644 --- a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt @@ -62,7 +62,7 @@ class FileMenuFilterIT : AbstractIT() { private lateinit var mockFileUploaderBinder: FileUploader.FileUploaderBinder @MockK - private lateinit var mockFileDownloaderBinder: FileDownloadWorker.FileDownloaderBinder + private lateinit var mockFileDownloadProgressListener: FileDownloadWorker.FileDownloadProgressListener @MockK private lateinit var mockOperationsServiceBinder: OperationsService.OperationsServiceBinder @@ -77,8 +77,8 @@ class FileMenuFilterIT : AbstractIT() { MockKAnnotations.init(this) every { mockFileUploaderBinder.isUploading(any(), any()) } returns false every { mockComponentsGetter.fileUploaderBinder } returns mockFileUploaderBinder - every { mockFileDownloaderBinder.isDownloading(any(), any()) } returns false - every { mockComponentsGetter.fileDownloaderBinder } returns mockFileDownloaderBinder + every { mockFileDownloadProgressListener.isDownloading(any(), any()) } returns false + every { mockComponentsGetter.fileDownloadProgressListener } returns mockFileDownloadProgressListener every { mockOperationsServiceBinder.isSynchronizing(any(), any()) } returns false every { mockComponentsGetter.operationsServiceBinder } returns mockOperationsServiceBinder every { mockStorageManager.getFileById(any()) } returns OCFile("/") diff --git a/app/src/debug/java/com/nextcloud/test/TestActivity.kt b/app/src/debug/java/com/nextcloud/test/TestActivity.kt index ec98df551af0..23297a32851c 100644 --- a/app/src/debug/java/com/nextcloud/test/TestActivity.kt +++ b/app/src/debug/java/com/nextcloud/test/TestActivity.kt @@ -130,7 +130,7 @@ class TestActivity : return null } - override fun getFileDownloaderBinder(): FileDownloadWorker.FileDownloaderBinder? { + override fun getFileDownloadProgressListener(): FileDownloadWorker.FileDownloadProgressListener? { return null } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index c9c17bf6dca5..e4d7ce201ebe 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -27,13 +27,14 @@ import com.owncloud.android.MainApp import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager +import com.owncloud.android.lib.common.network.OnDatatransferProgressListener import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType import com.owncloud.android.utils.MimeTypeUtil import java.io.File import javax.inject.Inject -class FileDownloadHelper { +class FileDownloadHelper : OnDatatransferProgressListener { @Inject lateinit var backgroundJobManager: BackgroundJobManager @@ -41,10 +42,51 @@ class FileDownloadHelper { @Inject lateinit var uploadsStorageManager: UploadsStorageManager + private val boundListeners: MutableMap = HashMap() + private var currentDownload: DownloadFileOperation? = null + init { MainApp.getAppComponent().inject(this) } + fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { + if (file == null || listener == null) { + return + } + + boundListeners[file.fileId] = listener + } + + fun removeDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { + if (file == null || listener == null) { + return + } + + val fileId = file.fileId + if (boundListeners[fileId] === listener) { + boundListeners.remove(fileId) + } + } + + override fun onTransferProgress( + progressRate: Long, + totalTransferredSoFar: Long, + totalToTransfer: Long, + fileName: String + ) { + val listener = boundListeners[currentDownload?.file?.fileId] + listener?.onTransferProgress( + progressRate, + totalTransferredSoFar, + totalToTransfer, + fileName + ) + } + + fun setCurrentDownload(operation: DownloadFileOperation) { + currentDownload = operation + } + fun isDownloading(user: User?, file: OCFile?): Boolean { return user != null && file != null && backgroundJobManager.isStartFileDownloadJobScheduled( user, @@ -52,6 +94,23 @@ class FileDownloadHelper { ) } + fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { + if (user == null || file == null) return + backgroundJobManager.cancelFilesDownloadJob(user, file) + } + + fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation) { + if (currentDownload.user.nameEquals(accountName)) { + currentDownload.file?.let { file -> + backgroundJobManager.cancelFilesDownloadJob(currentDownload.user, file) + } + + currentDownload.cancel() + } + + // removePendingDownload(accountName) + } + fun saveFile( file: OCFile, currentDownload: DownloadFileOperation?, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index c0fb808a22bc..c432f253e052 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -26,8 +26,6 @@ import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener import android.app.PendingIntent import android.content.Context -import android.os.Binder -import android.os.IBinder import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters @@ -97,12 +95,13 @@ class FileDownloadWorker( private val intents = FileDownloadIntents(context) private val notificationManager = DownloadNotificationManager(context, viewThemeUtils) private val pendingDownloads = IndexedForest() - private var downloadBinder: IBinder = FileDownloaderBinder() + private var downloadProgressListener = FileDownloadProgressListener() private var currentUser = Optional.empty() private val helper = FileDownloadHelper() private var startedDownload = false private var storageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null + private var user: User? = null private val gson = Gson() @Suppress("TooGenericExceptionCaught") @@ -122,11 +121,16 @@ class FileDownloadWorker( } } + override fun onStopped() { + super.onStopped() + setIdleWorkerState() + } + private fun getRequestDownloads(): AbstractList { conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) val accountName = inputData.keyValueMap[USER_NAME] as String - val user = accountManager.getUser(accountName).get() + user = accountManager.getUser(accountName).get() val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? val downloadType = if (downloadTypeAsString != null) { if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { @@ -140,7 +144,6 @@ class FileDownloadWorker( val behaviour = inputData.keyValueMap[BEHAVIOUR] as String val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String val packageName = inputData.keyValueMap[PACKAGE_NAME] as String - setWorkerState(user, file) val requestedDownloads: AbstractList = Vector() @@ -156,7 +159,7 @@ class FileDownloadWorker( ) operation.addDownloadDataTransferProgressListener(this) - operation.addDownloadDataTransferProgressListener(downloadBinder as FileDownloaderBinder) + operation.addDownloadDataTransferProgressListener(downloadProgressListener) val putResult = pendingDownloads.putIfAbsent( user?.accountName, file.remotePath, @@ -176,10 +179,14 @@ class FileDownloadWorker( } } - private fun setWorkerState(user: User, file: OCFile) { + private fun setWorkerState(user: User?, file: DownloadFileOperation?) { WorkerStateLiveData.instance?.setWorkState(WorkerState.Download(user, file)) } + private fun setIdleWorkerState() { + WorkerStateLiveData.instance?.setWorkState(WorkerState.Idle) + } + private fun addAccountUpdateListener() { val am = AccountManager.get(context) am.addOnAccountsUpdatedListener(this, null, false) @@ -205,6 +212,7 @@ class FileDownloadWorker( if (currentDownload == null) { return } + setWorkerState(user, currentDownload) val isAccountExist = accountManager.exists(currentDownload?.user?.toPlatformAccount()) if (!isAccountExist) { @@ -354,34 +362,11 @@ class FileDownloadWorker( lastPercent = percent } - inner class FileDownloaderBinder : Binder(), OnDatatransferProgressListener { + inner class FileDownloadProgressListener : OnDatatransferProgressListener { private val boundListeners: MutableMap = HashMap() - fun cancelPendingOrCurrentDownloads() { - currentDownload?.file?.let { file -> - helper.backgroundJobManager.cancelFilesDownloadJob(currentUser.get(), file) - } - } - - fun cancelAllDownloadsForAccount(accountName: String?) { - currentDownload?.user?.let { - if (it.nameEquals(accountName)) { - currentDownload?.file?.let { file -> - helper.backgroundJobManager.cancelFilesDownloadJob(it, file) - } - - currentDownload?.cancel() - } - } - - removePendingDownload(accountName) - } - fun isDownloading(user: User?, file: OCFile?): Boolean { - return user != null && file != null && helper.backgroundJobManager.isStartFileDownloadJobScheduled( - user, - file - ) + return helper.isDownloading(user, file) } fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { diff --git a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt index f15896692b6d..2c7d4e41b4e4 100644 --- a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt @@ -89,7 +89,7 @@ class DownloadNotificationManager(private val context: Context, private val view val notifyId = SecureRandom().nextInt() val contentText = if (result.isSuccess) { - download.file.fileName + " " + context.getString(R.string.downloader_download_succeeded_ticker) + download.file.fileName } else { ErrorMessageAdapter.getErrorCauseMessage( result, diff --git a/app/src/main/java/com/nextcloud/model/WorkerState.kt b/app/src/main/java/com/nextcloud/model/WorkerState.kt index 1bf8a78f2847..5bca9bb62b80 100644 --- a/app/src/main/java/com/nextcloud/model/WorkerState.kt +++ b/app/src/main/java/com/nextcloud/model/WorkerState.kt @@ -22,9 +22,9 @@ package com.nextcloud.model import com.nextcloud.client.account.User -import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.operations.DownloadFileOperation sealed class WorkerState { - object Idle - class Download(var user: User, var file: OCFile): WorkerState() + object Idle : WorkerState() + class Download(var user: User?, var currentDownload: DownloadFileOperation?) : WorkerState() } diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index 22b942e01003..6639a201c320 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -32,7 +32,6 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.editimage.EditImageActivity; import com.nextcloud.client.files.downloader.FileDownloadHelper; -import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.utils.EditorUtils; import com.owncloud.android.R; import com.owncloud.android.datamodel.FileDataStorageManager; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java index 48cc4986a99e..0a9c2be2a19b 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java @@ -32,9 +32,9 @@ public interface ComponentsGetter { * To be invoked when the parent activity is fully created to get a reference * to the FileDownloadWorker. */ - public FileDownloadWorker.FileDownloaderBinder getFileDownloaderBinder(); + public FileDownloadWorker.FileDownloadProgressListener getFileDownloadProgressListener(); + - /** * To be invoked when the parent activity is fully created to get a reference * to the FileUploader service API. diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index 11910ca5cd93..fb0c623fabdc 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -167,7 +167,7 @@ public abstract class FileActivity extends DrawerActivity private boolean mResumed; protected FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); - protected FileDownloadWorker.FileDownloaderBinder mDownloaderBinder; + protected FileDownloadWorker.FileDownloadProgressListener fileDownloadProgressListener; protected FileUploaderBinder mUploaderBinder; private ServiceConnection mUploadServiceConnection; @@ -613,8 +613,8 @@ public void onServiceDisconnected(ComponentName component) { } @Override - public FileDownloadWorker.FileDownloaderBinder getFileDownloaderBinder() { - return mDownloaderBinder; + public FileDownloadWorker.FileDownloadProgressListener getFileDownloadProgressListener() { + return fileDownloadProgressListener; } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 6635bf855926..a0e94413e315 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -65,7 +65,6 @@ import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; import com.nextcloud.client.files.DeepLinkHandler; -import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.media.PlayerServiceConnection; import com.nextcloud.client.network.ClientFactory; @@ -162,7 +161,6 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; -import androidx.lifecycle.Observer; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import kotlin.Unit; @@ -1620,7 +1618,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { public void onServiceDisconnected(ComponentName component) { if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloadWorker.class))) { Log_OC.d(TAG, "Download service disconnected"); - mDownloaderBinder = null; + fileDownloadProgressListener = null; } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service disconnected"); mUploaderBinder = null; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index b0d200277393..a26c4f95c13e 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -41,10 +41,11 @@ import com.google.common.collect.Sets; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; -import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.onboarding.FirstRunActivity; import com.nextcloud.java.util.Optional; +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; @@ -56,6 +57,7 @@ import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.UserInfo; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.operations.DownloadFileOperation; import com.owncloud.android.services.OperationsService; import com.owncloud.android.ui.adapter.UserListAdapter; import com.owncloud.android.ui.adapter.UserListItem; @@ -112,6 +114,9 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap private ArbitraryDataProvider arbitraryDataProvider; private boolean multipleAccountsSupported; + private String workerAccountName; + private DownloadFileOperation workerCurrentDownload; + @Inject BackgroundJobManager backgroundJobManager; @Inject UserAccountManager accountManager; @@ -159,6 +164,7 @@ protected void onCreate(Bundle savedInstanceState) { recyclerView.setAdapter(userListAdapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); initializeComponentGetters(); + observeWorkerState(); } @@ -334,9 +340,8 @@ public void run(AccountManagerFuture future) { if (mUploaderBinder != null) { mUploaderBinder.cancel(accountName); } - if (mDownloaderBinder != null) { - mDownloaderBinder.cancelAllDownloadsForAccount(accountName); - } + + fileDownloadHelper.cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); } User currentUser = getUserAccountManager().getUser(); @@ -425,9 +430,8 @@ private void performAccountRemoval(User user) { if (mUploaderBinder != null) { mUploaderBinder.cancel(user); } - if (mDownloaderBinder != null) { - mDownloaderBinder.cancelAllDownloadsForAccount(user.getAccountName()); - } + + fileDownloadHelper.cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); backgroundJobManager.startAccountRemovalJob(user.getAccountName(), false); @@ -512,6 +516,16 @@ public void onOptionItemClicked(User user, View view) { } } + private void observeWorkerState() { + WorkerStateLiveData.Companion.getInstance().observe(this, state -> { + if (state instanceof WorkerState.Download) { + Log_OC.d(TAG, "Download worker started"); + workerAccountName = ((WorkerState.Download) state).getUser().getAccountName(); + workerCurrentDownload = ((WorkerState.Download) state).getCurrentDownload(); + } + }); + } + @Override public void onAccountClicked(User user) { openAccount(user); @@ -524,11 +538,7 @@ private class ManageAccountsServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { - - if (component.equals(new ComponentName(ManageAccountsActivity.this, FileDownloadWorker.class))) { - mDownloaderBinder = (FileDownloadWorker.FileDownloaderBinder) service; - - } else if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { + if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service connected"); mUploaderBinder = (FileUploader.FileUploaderBinder) service; } @@ -536,10 +546,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { - if (component.equals(new ComponentName(ManageAccountsActivity.this, FileDownloadWorker.class))) { - Log_OC.d(TAG, "Download service suddenly disconnected"); - mDownloaderBinder = null; - } else if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { + if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service suddenly disconnected"); mUploaderBinder = null; } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 55c9f6700798..1801404df9f4 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -45,7 +45,6 @@ import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.files.downloader.FileDownloadHelper; -import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ClientFactory; import com.nextcloud.client.network.ConnectivityService; @@ -694,8 +693,8 @@ private void setButtonsForRemote() { public void listenForTransferProgress() { if (progressListener != null) { - if (containerActivity.getFileDownloaderBinder() != null) { - containerActivity.getFileDownloaderBinder(). + if (containerActivity.getFileDownloadProgressListener() != null) { + containerActivity.getFileDownloadProgressListener(). addDataTransferProgressListener(progressListener, getFile()); } if (containerActivity.getFileUploaderBinder() != null) { @@ -709,8 +708,8 @@ public void listenForTransferProgress() { private void leaveTransferProgress() { if (progressListener != null) { - if (containerActivity.getFileDownloaderBinder() != null) { - containerActivity.getFileDownloaderBinder(). + if (containerActivity.getFileDownloadProgressListener() != null) { + containerActivity.getFileDownloadProgressListener(). removeDataTransferProgressListener(progressListener, getFile()); } if (containerActivity.getFileUploaderBinder() != null) { diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index d6cb6f325597..a072ddd7cd23 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -48,7 +48,6 @@ import com.nextcloud.client.account.CurrentAccountProvider; import com.nextcloud.client.account.User; import com.nextcloud.client.files.downloader.FileDownloadHelper; -import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.java.util.Optional; @@ -998,9 +997,9 @@ public void cancelTransference(OCFile file) { } // for both files and folders - FileDownloadWorker.FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder(); - if (downloaderBinder != null && downloaderBinder.isDownloading(currentUser, file)) { - downloaderBinder.cancelPendingOrCurrentDownloads(); + FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); + if (fileDownloadHelper.isDownloading(currentUser, file)) { + fileDownloadHelper.cancelPendingOrCurrentDownloads(currentUser, file); } FileUploaderBinder uploaderBinder = fileActivity.getFileUploaderBinder(); if (uploaderBinder != null && uploaderBinder.isUploading(currentUser, file)) { diff --git a/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java index d7c05e595409..4aa7a19ba7c5 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java @@ -261,8 +261,8 @@ private void setButtonsForRemote() { public void listenForTransferProgress() { - if (mProgressListener != null && !mListening && containerActivity.getFileDownloaderBinder() != null) { - containerActivity.getFileDownloaderBinder().addDataTransferProgressListener(mProgressListener, getFile()); + if (mProgressListener != null && !mListening && containerActivity.getFileDownloadProgressListener() != null) { + containerActivity.getFileDownloadProgressListener().addDataTransferProgressListener(mProgressListener, getFile()); mListening = true; setButtonsForTransferring(); } @@ -270,8 +270,8 @@ public void listenForTransferProgress() { public void leaveTransferProgress() { - if (mProgressListener != null && containerActivity.getFileDownloaderBinder() != null) { - containerActivity.getFileDownloaderBinder() + if (mProgressListener != null && containerActivity.getFileDownloadProgressListener() != null) { + containerActivity.getFileDownloadProgressListener() .removeDataTransferProgressListener(mProgressListener, getFile()); mListening = false; } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index aacea713eb58..34a26831e63e 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -37,10 +37,11 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; -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.WorkerState; +import com.nextcloud.model.WorkerStateLiveData; import com.nextcloud.utils.extensions.IntentExtensionsKt; import com.owncloud.android.MainApp; import com.owncloud.android.R; @@ -99,6 +100,8 @@ public class PreviewImageActivity extends FileActivity implements private DownloadFinishReceiver mDownloadFinishReceiver; private UploadFinishReceiver mUploadFinishReceiver; private View mFullScreenAnchorView; + private boolean isDownloadWorkStarted = false; + @Inject AppPreferences preferences; @Inject LocalBroadcastManager localBroadcastManager; @@ -146,6 +149,8 @@ protected void onCreate(Bundle savedInstanceState) { } else { mRequestWaitingForBinder = false; } + + observeWorkerState(); } public void toggleActionBarVisibility(boolean hide) { @@ -299,6 +304,25 @@ private void onSynchronizeFileOperationFinish(RemoteOperationResult result) { } } + private void observeWorkerState() { + WorkerStateLiveData.Companion.getInstance().observe(this, state -> { + if (state instanceof WorkerState.Download) { + Log_OC.d(TAG, "Download worker started"); + isDownloadWorkStarted = true; + + if (mRequestWaitingForBinder) { + mRequestWaitingForBinder = false; + Log_OC.d(TAG, "Simulating reselection of current page after connection " + + "of download binder"); + onPageSelected(mViewPager.getCurrentItem()); + } + } else { + Log_OC.d(TAG, "Download worker stopped"); + isDownloadWorkStarted = false; + } + }); + } + @Override protected ServiceConnection newTransferenceServiceConnection() { return new PreviewImageServiceConnection(); @@ -309,18 +333,7 @@ private class PreviewImageServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { - if (component.equals(new ComponentName(PreviewImageActivity.this, - FileDownloadWorker.class))) { - mDownloaderBinder = (FileDownloadWorker.FileDownloaderBinder) service; - if (mRequestWaitingForBinder) { - mRequestWaitingForBinder = false; - Log_OC.d(TAG, "Simulating reselection of current page after connection " + - "of download binder"); - onPageSelected(mViewPager.getCurrentItem()); - } - - } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service connected"); mUploaderBinder = (FileUploaderBinder) service; @@ -331,10 +344,6 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { if (component.equals(new ComponentName(PreviewImageActivity.this, - FileDownloadWorker.class))) { - Log_OC.d(TAG, "Download service suddenly disconnected"); - mDownloaderBinder = null; - } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service suddenly disconnected"); mUploaderBinder = null; @@ -425,7 +434,7 @@ public void requestForDownload(OCFile file, String downloadBehaviour) { public void onPageSelected(int position) { mSavedPosition = position; mHasSavedPosition = true; - if (mDownloaderBinder == null) { + if (!isDownloadWorkStarted) { mRequestWaitingForBinder = true; } else { OCFile currentFile = mPreviewImagePagerAdapter.getFileAt(position); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java index f09d51f0451f..e0d4573bc457 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java @@ -19,7 +19,6 @@ */ package com.owncloud.android.ui.preview; -import android.content.Intent; import android.util.SparseArray; import android.view.ViewGroup; diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt index 8de694773eed..8e6d15c2f9ef 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt @@ -27,9 +27,7 @@ package com.owncloud.android.ui.preview import android.app.Activity -import android.content.ComponentName import android.content.Intent -import android.content.ServiceConnection import android.content.res.Configuration import android.graphics.Bitmap import android.graphics.BitmapFactory @@ -39,7 +37,6 @@ import android.net.Uri import android.os.AsyncTask import android.os.Bundle import android.os.Handler -import android.os.IBinder import android.os.Looper import android.view.Menu import android.view.MenuItem @@ -65,8 +62,6 @@ import androidx.media3.ui.PlayerView import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.di.Injectable -import com.nextcloud.client.files.downloader.FileDownloadHelper -import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.client.jobs.BackgroundJobManager import com.nextcloud.client.media.ExoplayerListener import com.nextcloud.client.media.NextcloudExoPlayer.createNextcloudExoplayer @@ -563,33 +558,12 @@ class PreviewMediaActivity : } } - override fun newTransferenceServiceConnection(): ServiceConnection { - return PreviewMediaServiceConnection() - } - private fun onSynchronizeFileOperationFinish(result: RemoteOperationResult<*>?) { result?.let { invalidateOptionsMenu() } } - private inner class PreviewMediaServiceConnection : ServiceConnection { - override fun onServiceConnected(componentName: ComponentName?, service: IBinder?) { - componentName?.let { - if (it == ComponentName(this@PreviewMediaActivity, FileDownloadWorker::class.java)) { - mDownloaderBinder = service as FileDownloadWorker.FileDownloaderBinder - } - } - } - - override fun onServiceDisconnected(componentName: ComponentName?) { - if (componentName == ComponentName(this@PreviewMediaActivity, FileDownloadWorker::class.java)) { - Log_OC.d(PreviewImageActivity.TAG, "Download service suddenly disconnected") - mDownloaderBinder = null - } - } - } - override fun downloadFile(file: OCFile?, packageName: String?, activityName: String?) { requestForDownload(file, OCFileListFragment.DOWNLOAD_SEND, packageName, activityName) } From 680f31edef7021daf10bf2c2e1946f6e6abb4aa8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 14:15:43 +0100 Subject: [PATCH 043/189] Fix code analytics Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 124 ++++-------------- .../files/downloader/FileDownloadWorker.kt | 5 +- .../nextcloud/client/jobs/FilesExportWork.kt | 4 +- .../android/files/FileMenuFilter.java | 7 +- .../operations/SynchronizeFileOperation.java | 13 +- .../SynchronizeFolderOperation.java | 4 +- .../ui/activity/ConflictsResolveActivity.kt | 4 +- .../android/ui/activity/FileActivity.java | 3 +- .../ui/activity/FileDisplayActivity.java | 9 +- .../ui/activity/ManageAccountsActivity.java | 5 +- .../android/ui/adapter/OCFileListDelegate.kt | 26 ++-- .../ui/fragment/FileDetailFragment.java | 6 +- .../ui/helpers/FileOperationsHelper.java | 7 +- .../ui/preview/PreviewImageActivity.java | 6 +- .../ui/preview/PreviewMediaActivity.kt | 7 +- .../ui/preview/PreviewMediaFragment.java | 5 +- 16 files changed, 71 insertions(+), 164 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index e4d7ce201ebe..189b6263dba0 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -27,14 +27,13 @@ import com.owncloud.android.MainApp import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager -import com.owncloud.android.lib.common.network.OnDatatransferProgressListener import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType import com.owncloud.android.utils.MimeTypeUtil import java.io.File import javax.inject.Inject -class FileDownloadHelper : OnDatatransferProgressListener { +class FileDownloadHelper { @Inject lateinit var backgroundJobManager: BackgroundJobManager @@ -42,49 +41,20 @@ class FileDownloadHelper : OnDatatransferProgressListener { @Inject lateinit var uploadsStorageManager: UploadsStorageManager - private val boundListeners: MutableMap = HashMap() - private var currentDownload: DownloadFileOperation? = null + companion object { + private var instance: FileDownloadHelper? = null - init { - MainApp.getAppComponent().inject(this) - } - - fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { - if (file == null || listener == null) { - return - } - - boundListeners[file.fileId] = listener - } - - fun removeDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { - if (file == null || listener == null) { - return - } - - val fileId = file.fileId - if (boundListeners[fileId] === listener) { - boundListeners.remove(fileId) + fun instance(): FileDownloadHelper { + return if (instance == null) { + FileDownloadHelper() + } else { + instance!! + } } } - override fun onTransferProgress( - progressRate: Long, - totalTransferredSoFar: Long, - totalToTransfer: Long, - fileName: String - ) { - val listener = boundListeners[currentDownload?.file?.fileId] - listener?.onTransferProgress( - progressRate, - totalTransferredSoFar, - totalToTransfer, - fileName - ) - } - - fun setCurrentDownload(operation: DownloadFileOperation) { - currentDownload = operation + init { + MainApp.getAppComponent().inject(this) } fun isDownloading(user: User?, file: OCFile?): Boolean { @@ -145,75 +115,25 @@ class FileDownloadHelper : OnDatatransferProgressListener { storageManager?.saveConflict(file, null) } - fun downloadFile(user: User, ocFile: OCFile) { - backgroundJobManager.startFileDownloadJob( - user, - ocFile, - "", - DownloadType.DOWNLOAD, - "", - "", - null - ) - } - - fun downloadFile(user: User, ocFile: OCFile, behaviour: String) { - backgroundJobManager.startFileDownloadJob( - user, - ocFile, - behaviour, - DownloadType.DOWNLOAD, - "", - "", - null - ) - } - - fun downloadFile(user: User, ocFile: OCFile, behaviour: String, packageName: String, activityName: String) { - backgroundJobManager.startFileDownloadJob( - user, - ocFile, - behaviour, - DownloadType.DOWNLOAD, - packageName, - packageName, - null - ) - } - - fun downloadFile(user: User, ocFile: OCFile, downloadType: DownloadType) { - backgroundJobManager.startFileDownloadJob( - user, - ocFile, - "", - downloadType, - "", - "", - null - ) + fun downloadFileIfNotStartedBefore(user: User, file: OCFile) { + if (!isDownloading(user, file)) { + downloadFile(user, file, downloadType = DownloadType.DOWNLOAD) + } } - fun downloadFile(user: User, ocFile: OCFile, conflictUploadId: Long) { - backgroundJobManager.startFileDownloadJob( - user, - ocFile, - "", - DownloadType.DOWNLOAD, - "", - "", - conflictUploadId - ) + fun downloadFile(user: User, ocFile: OCFile) { + downloadFile(user, ocFile, downloadType = DownloadType.DOWNLOAD) } @Suppress("LongParameterList") fun downloadFile( user: User, ocFile: OCFile, - behaviour: String, - downloadType: DownloadType?, - activityName: String, - packageName: String, - conflictUploadId: Long? + behaviour: String = "", + downloadType: DownloadType? = DownloadType.DOWNLOAD, + activityName: String = "", + packageName: String = "", + conflictUploadId: Long? = null ) { backgroundJobManager.startFileDownloadJob( user, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index c432f253e052..0dde3df25d41 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -97,7 +97,6 @@ class FileDownloadWorker( private val pendingDownloads = IndexedForest() private var downloadProgressListener = FileDownloadProgressListener() private var currentUser = Optional.empty() - private val helper = FileDownloadHelper() private var startedDownload = false private var storageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null @@ -230,7 +229,7 @@ class FileDownloadWorker( downloadResult = currentDownload?.execute(downloadClient) if (downloadResult?.isSuccess == true && currentDownload?.downloadType === DownloadType.DOWNLOAD) { getCurrentFile()?.let { - helper.saveFile(it, currentDownload, storageManager) + FileDownloadHelper.instance().saveFile(it, currentDownload, storageManager) } } } catch (e: Exception) { @@ -366,7 +365,7 @@ class FileDownloadWorker( private val boundListeners: MutableMap = HashMap() fun isDownloading(user: User?, file: OCFile?): Boolean { - return helper.isDownloading(user, file) + return FileDownloadHelper.instance().isDownloading(user, file) } fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt index c5f82cc89df2..05586ba96569 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt @@ -111,10 +111,10 @@ class FilesExportWork( } private fun downloadFile(ocFile: OCFile) { - FileDownloadHelper().downloadFile( + FileDownloadHelper.instance().downloadFile( user, ocFile, - DownloadType.EXPORT + downloadType = DownloadType.EXPORT ) } diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index 6639a201c320..e209d21bc301 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -380,9 +380,8 @@ private boolean anyFileSynchronizing() { if (componentsGetter != null && !files.isEmpty() && user != null) { OperationsServiceBinder opsBinder = componentsGetter.getOperationsServiceBinder(); FileUploaderBinder uploaderBinder = componentsGetter.getFileUploaderBinder(); - FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); synchronizing = anyFileSynchronizing(opsBinder) || // comparing local and remote - anyFileDownloading(fileDownloadHelper) || + anyFileDownloading() || anyFileUploading(uploaderBinder); } return synchronizing; @@ -398,9 +397,9 @@ private boolean anyFileSynchronizing(OperationsServiceBinder opsBinder) { return synchronizing; } - private boolean anyFileDownloading(FileDownloadHelper downloadHelper) { + private boolean anyFileDownloading() { for (OCFile file : files) { - if (downloadHelper.isDownloading(user, file)) { + if (FileDownloadHelper.Companion.instance().isDownloading(user, file)) { return true; } } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java index 48b7aa9b701f..e993df4f66f4 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -309,30 +309,19 @@ private void requestForUpload(OCFile file) { mTransferWasRequested = true; } - - /** - * Requests for a download to the FileDownloader service - * - * @param file OCFile object representing the file to download - */ private void requestForDownload(OCFile file) { - FileDownloadHelper downloadHelper = new FileDownloadHelper(); - - downloadHelper.downloadFile( + FileDownloadHelper.Companion.instance().downloadFile( mUser, file); mTransferWasRequested = true; } - public boolean transferWasRequested() { return mTransferWasRequested; } - public OCFile getLocalFile() { return mLocalFile; } - } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index 0cb9cff609e8..d6228d3d67bd 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -445,14 +445,12 @@ private void syncContents() throws OperationCancelledException { } private void startDirectDownloads() throws OperationCancelledException { - FileDownloadHelper downloadHelper = new FileDownloadHelper(); - for (OCFile file : mFilesForDirectDownload) { synchronized(mCancellationRequested) { if (mCancellationRequested.get()) { throw new OperationCancelledException(); } - downloadHelper.downloadFile(user, file); + FileDownloadHelper.Companion.instance().downloadFile(user, file); } } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt index 0a1f8d3bffbe..b85f3925c5e1 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt @@ -115,10 +115,10 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener Decision.KEEP_SERVER -> if (!shouldDeleteLocal()) { // Overwrite local file file?.let { - FileDownloadHelper().downloadFile( + FileDownloadHelper.instance().downloadFile( getUser().orElseThrow { RuntimeException() }, file, - conflictUploadId + conflictUploadId = conflictUploadId ) } } else { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index fb0c623fabdc..fca1cbd96bc1 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -166,7 +166,6 @@ public abstract class FileActivity extends DrawerActivity private boolean mResumed; - protected FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); protected FileDownloadWorker.FileDownloadProgressListener fileDownloadProgressListener; protected FileUploaderBinder mUploaderBinder; private ServiceConnection mUploadServiceConnection; @@ -235,7 +234,7 @@ protected void onCreate(Bundle savedInstanceState) { Context.BIND_AUTO_CREATE); if (user != null) { - new FileDownloadHelper().downloadFile(user, mFile); + FileDownloadHelper.Companion.instance().downloadFile(user, mFile); } mUploadServiceConnection = newTransferenceServiceConnection(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index a0e94413e315..543d2a982dbe 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -65,6 +65,7 @@ import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; import com.nextcloud.client.files.DeepLinkHandler; +import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.media.PlayerServiceConnection; import com.nextcloud.client.network.ClientFactory; @@ -1896,9 +1897,7 @@ public void onTransferStateChanged(OCFile file, boolean downloading, boolean upl private void requestForDownload() { User user = getUser().orElseThrow(RuntimeException::new); - if (!fileDownloadHelper.isDownloading(user, mWaitingToPreview)) { - fileDownloadHelper.downloadFile(user, mWaitingToPreview); - } + FileDownloadHelper.Companion.instance().downloadFileIfNotStartedBefore(user, mWaitingToPreview); } @Override @@ -1968,8 +1967,8 @@ public void run() { private void requestForDownload(OCFile file, String downloadBehaviour, String packageName, String activityName) { final User currentUser = getUser().orElseThrow(RuntimeException::new); - if (!fileDownloadHelper.isDownloading(currentUser, file)) { - fileDownloadHelper.downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); + if (!FileDownloadHelper.Companion.instance().isDownloading(currentUser, file)) { + FileDownloadHelper.Companion.instance().downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index a26c4f95c13e..29f102988a2a 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -41,6 +41,7 @@ import com.google.common.collect.Sets; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; +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; @@ -341,7 +342,7 @@ public void run(AccountManagerFuture future) { mUploaderBinder.cancel(accountName); } - fileDownloadHelper.cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); + FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); } User currentUser = getUserAccountManager().getUser(); @@ -431,7 +432,7 @@ private void performAccountRemoval(User user) { mUploaderBinder.cancel(user); } - fileDownloadHelper.cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); + FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); backgroundJobManager.startAccountRemovalJob(user.getAccountName(), false); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 5cd63ffe60c8..9b430135b56f 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -341,27 +341,31 @@ class OCFileListDelegate( private fun showLocalFileIndicator(file: OCFile, gridViewHolder: ListGridImageViewHolder) { val operationsServiceBinder = transferServiceGetter.operationsServiceBinder - val fileDownloadHelper = FileDownloadHelper() val fileUploaderBinder = transferServiceGetter.fileUploaderBinder - when { + + val icon: Int? = when { operationsServiceBinder?.isSynchronizing(user, file) == true || - fileDownloadHelper.isDownloading(user, file) || + FileDownloadHelper.instance().isDownloading(user, file) || fileUploaderBinder?.isUploading(user, file) == true -> { // synchronizing, downloading or uploading - gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing) - gridViewHolder.localFileIndicator.visibility = View.VISIBLE + R.drawable.ic_synchronizing } file.etagInConflict != null -> { - // conflict - gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing_error) - gridViewHolder.localFileIndicator.visibility = View.VISIBLE + R.drawable.ic_synchronizing_error } file.isDown -> { - // downloaded - gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synced) - gridViewHolder.localFileIndicator.visibility = View.VISIBLE + R.drawable.ic_synced } + else -> { null } } + + gridViewHolder.localFileIndicator.run { + icon?.let { + setImageResource(icon) + visibility = View.VISIBLE + } + } + } private fun showShareIcon(gridViewHolder: ListGridImageViewHolder, file: OCFile) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 1801404df9f4..cecc01838c49 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -534,10 +534,9 @@ public void updateFileDetails(boolean transferring, boolean refresh) { setFavoriteIconStatus(file.isFavorite()); // configure UI for depending upon local state of the file - FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); if (transferring - || (fileDownloadHelper.isDownloading(user, file)) + || (FileDownloadHelper.Companion.instance().isDownloading(user, file)) || (uploaderBinder != null && uploaderBinder.isUploading(user, file))) { setButtonsForTransferring(); @@ -659,9 +658,8 @@ private void setButtonsForTransferring() { // show the progress bar for the transfer binding.progressBlock.setVisibility(View.VISIBLE); binding.progressText.setVisibility(View.VISIBLE); - FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); - if (fileDownloadHelper.isDownloading(user, getFile())) { + if (FileDownloadHelper.Companion.instance().isDownloading(user, getFile())) { binding.progressText.setText(R.string.downloader_download_in_progress_ticker); } else { if (uploaderBinder != null && uploaderBinder.isUploading(user, getFile())) { diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index a072ddd7cd23..69ee619382b2 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -996,11 +996,10 @@ public void cancelTransference(OCFile file) { } } - // for both files and folders - FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); - if (fileDownloadHelper.isDownloading(currentUser, file)) { - fileDownloadHelper.cancelPendingOrCurrentDownloads(currentUser, file); + if (FileDownloadHelper.Companion.instance().isDownloading(currentUser, file)) { + FileDownloadHelper.Companion.instance().cancelPendingOrCurrentDownloads(currentUser, file); } + FileUploaderBinder uploaderBinder = fileActivity.getFileUploaderBinder(); if (uploaderBinder != null && uploaderBinder.isUploading(currentUser, file)) { uploaderBinder.cancel(currentUser.toPlatformAccount(), file); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 34a26831e63e..8915ed9c1b46 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -37,6 +37,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; +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; @@ -54,6 +55,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.operations.DownloadType; import com.owncloud.android.operations.RemoveFileOperation; import com.owncloud.android.operations.SynchronizeFileOperation; import com.owncloud.android.ui.activity.FileActivity; @@ -419,8 +421,8 @@ public void requestForDownload(OCFile file) { public void requestForDownload(OCFile file, String downloadBehaviour) { final User user = getUser().orElseThrow(RuntimeException::new); - if (!fileDownloadHelper.isDownloading(user, file)) { - fileDownloadHelper.downloadFile(user, file, downloadBehaviour); + if (!FileDownloadHelper.Companion.instance().isDownloading(user, file)) { + FileDownloadHelper.Companion.instance().downloadFile(user, file, downloadBehaviour, DownloadType.DOWNLOAD, "", "", null); } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt index 8e6d15c2f9ef..23d7bd00b40f 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt @@ -62,6 +62,7 @@ import androidx.media3.ui.PlayerView import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.di.Injectable +import com.nextcloud.client.files.downloader.FileDownloadHelper import com.nextcloud.client.jobs.BackgroundJobManager import com.nextcloud.client.media.ExoplayerListener import com.nextcloud.client.media.NextcloudExoPlayer.createNextcloudExoplayer @@ -82,6 +83,7 @@ import com.owncloud.android.lib.common.operations.OnRemoteOperationListener import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.operations.DownloadType import com.owncloud.android.operations.RemoveFileOperation import com.owncloud.android.operations.SynchronizeFileOperation import com.owncloud.android.ui.activity.FileActivity @@ -574,16 +576,17 @@ class PreviewMediaActivity : packageName: String? = null, activityName: String? = null ) { - if (fileDownloadHelper.isDownloading(user, file)) { + if (FileDownloadHelper.instance().isDownloading(user, file)) { return } user?.let { user -> file?.let { file -> - fileDownloadHelper.downloadFile( + FileDownloadHelper.instance().downloadFile( user, file, downloadBehavior ?: "", + DownloadType.DOWNLOAD, packageName ?: "", activityName ?: "" ) diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index 28c3e4d4f314..a1ef3e805734 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -131,7 +131,6 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene private boolean autoplay; private boolean isLivePhoto; - private final FileDownloadHelper downloadHelper = new FileDownloadHelper(); private boolean prepared; private PlayerServiceConnection mediaPlayerServiceConnection; @@ -479,9 +478,7 @@ public void onFileActionChosen(final int itemId) { getView(), backgroundJobManager); } else if (itemId == R.id.action_download_file) { - if (!downloadHelper.isDownloading(user, getFile())) { - downloadHelper.downloadFile(user, getFile()); - } + FileDownloadHelper.Companion.instance().downloadFileIfNotStartedBefore(user, getFile()); } } From 7b8be6b235d397072b306fe8aebc8c87d9342630 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 14:19:25 +0100 Subject: [PATCH 044/189] Fix code analytics Signed-off-by: alperozturk --- .../com/nextcloud/client/files/downloader/FileDownloadHelper.kt | 2 -- .../java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt | 1 - 2 files changed, 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 189b6263dba0..9af4f2162e3a 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -77,8 +77,6 @@ class FileDownloadHelper { currentDownload.cancel() } - - // removePendingDownload(accountName) } fun saveFile( diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 9b430135b56f..e4fef4e2999b 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -365,7 +365,6 @@ class OCFileListDelegate( visibility = View.VISIBLE } } - } private fun showShareIcon(gridViewHolder: ListGridImageViewHolder, file: OCFile) { From adb1269e0af437f60238ce25ebf0cb124b51f29a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 14:26:32 +0100 Subject: [PATCH 045/189] Fix code analytics Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadHelper.kt | 6 ++---- .../client/files/downloader/FileDownloadWorker.kt | 4 ++-- .../java/com/nextcloud/model/WorkerStateLiveData.kt | 13 ++++++------- .../android/ui/activity/FileDisplayActivity.java | 2 +- .../android/ui/activity/ManageAccountsActivity.java | 2 +- .../android/ui/preview/PreviewImageActivity.java | 2 +- 6 files changed, 13 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 9af4f2162e3a..cc175c2ce7e6 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -45,10 +45,8 @@ class FileDownloadHelper { private var instance: FileDownloadHelper? = null fun instance(): FileDownloadHelper { - return if (instance == null) { - FileDownloadHelper() - } else { - instance!! + return instance ?: synchronized(this) { + instance ?: FileDownloadHelper().also { instance = it } } } } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 0dde3df25d41..8b826be235c1 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -179,11 +179,11 @@ class FileDownloadWorker( } private fun setWorkerState(user: User?, file: DownloadFileOperation?) { - WorkerStateLiveData.instance?.setWorkState(WorkerState.Download(user, file)) + WorkerStateLiveData.instance().setWorkState(WorkerState.Download(user, file)) } private fun setIdleWorkerState() { - WorkerStateLiveData.instance?.setWorkState(WorkerState.Idle) + WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } private fun addAccountUpdateListener() { diff --git a/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt b/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt index 8863b6dddac2..54fd35f4d702 100644 --- a/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt +++ b/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt @@ -30,13 +30,12 @@ class WorkerStateLiveData private constructor() : LiveData() { } companion object { - var instance: WorkerStateLiveData? = null - get() { - if (field == null) { - field = WorkerStateLiveData() - } - return field + private var instance: WorkerStateLiveData? = null + + fun instance(): WorkerStateLiveData { + return instance ?: synchronized(this) { + instance ?: WorkerStateLiveData().also { instance = it } } - private set + } } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 543d2a982dbe..d54374c1c4e0 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1563,7 +1563,7 @@ public boolean isDrawerIndicatorAvailable() { } private void observeWorkerState() { - WorkerStateLiveData.Companion.getInstance().observe(this, state -> { + WorkerStateLiveData.Companion.instance().observe(this, state -> { if (state instanceof WorkerState.Download) { Log_OC.d(TAG, "Download worker started"); handleDownloadWorkerState(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 29f102988a2a..955c240d0857 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -518,7 +518,7 @@ public void onOptionItemClicked(User user, View view) { } private void observeWorkerState() { - WorkerStateLiveData.Companion.getInstance().observe(this, state -> { + WorkerStateLiveData.Companion.instance().observe(this, state -> { if (state instanceof WorkerState.Download) { Log_OC.d(TAG, "Download worker started"); workerAccountName = ((WorkerState.Download) state).getUser().getAccountName(); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 8915ed9c1b46..80c07b03d7a7 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -307,7 +307,7 @@ private void onSynchronizeFileOperationFinish(RemoteOperationResult result) { } private void observeWorkerState() { - WorkerStateLiveData.Companion.getInstance().observe(this, state -> { + WorkerStateLiveData.Companion.instance().observe(this, state -> { if (state instanceof WorkerState.Download) { Log_OC.d(TAG, "Download worker started"); isDownloadWorkStarted = true; From cb402939323e7e02b944e7816249a959886b12e8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 15:53:35 +0100 Subject: [PATCH 046/189] Fixes notification manager Signed-off-by: alperozturk --- .../AppNotificationManagerImpl.kt | 2 +- .../download/DownloadNotificationManager.kt | 88 ++++++++++--------- .../utils/extensions/ContextExtensions.kt | 5 -- app/src/main/res/values/strings.xml | 2 +- 4 files changed, 48 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/notifications/AppNotificationManagerImpl.kt b/app/src/main/java/com/nextcloud/client/notifications/AppNotificationManagerImpl.kt index 9f754f5fe76e..203802b15702 100644 --- a/app/src/main/java/com/nextcloud/client/notifications/AppNotificationManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/notifications/AppNotificationManagerImpl.kt @@ -45,7 +45,7 @@ class AppNotificationManagerImpl @Inject constructor( val icon = BitmapFactory.decodeResource(resources, R.drawable.notification_icon) return builder(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) .setContentTitle(resources.getString(R.string.app_name)) - .setContentText(resources.getString(R.string.foreground_service_download)) + .setContentText(resources.getString(R.string.worker_download)) .setSmallIcon(R.drawable.notification_icon) .setLargeIcon(icon) .build() diff --git a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt index 2c7d4e41b4e4..397e8a5191b9 100644 --- a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt @@ -48,14 +48,14 @@ class DownloadNotificationManager(private val context: Context, private val view private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager fun init() { - notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) - .setContentTitle(context.resources.getString(R.string.app_name)) - .setContentText(context.resources.getString(R.string.foreground_service_download)) - .setSmallIcon(R.drawable.notification_icon) - .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply { + setContentTitle(context.resources.getString(R.string.app_name)) + setContentText(context.resources.getString(R.string.worker_download)) + setSmallIcon(R.drawable.notification_icon) + setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + } } notification = notificationBuilder.build() @@ -63,44 +63,50 @@ class DownloadNotificationManager(private val context: Context, private val view @Suppress("MagicNumber") fun notifyForStart(operation: DownloadFileOperation) { - notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) - .setSmallIcon(R.drawable.notification_icon) - .setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) - .setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) - .setOngoing(true) - .setProgress(100, 0, operation.size < 0) - .setContentText( + notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply { + setSmallIcon(R.drawable.notification_icon) + setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) + setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) + setOngoing(true) + setProgress(100, 0, operation.size < 0) + setContentText( String.format( context.getString(R.string.downloader_download_in_progress_content), 0, File(operation.savePath).name ) ) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + } } } + fun prepareForResult( + downloadResult: RemoteOperationResult<*>, + needsToUpdateCredentials: Boolean + ) { + val tickerId = getTickerId(downloadResult.isSuccess, needsToUpdateCredentials) + + notificationBuilder + .setTicker(context.getString(tickerId)) + .setContentTitle(context.getString(tickerId)) + .setAutoCancel(true) + .setOngoing(false) + .setProgress(0, 0, false) + } + @Suppress("MagicNumber") fun notifyForResult(result: RemoteOperationResult<*>, download: DownloadFileOperation) { dismissDownloadInProgressNotification() val tickerId = getTickerId(result.isSuccess, null) val notifyId = SecureRandom().nextInt() - - val contentText = if (result.isSuccess) { - download.file.fileName - } else { - ErrorMessageAdapter.getErrorCauseMessage( - result, - download, - context.resources - ) - } + val resultText = getResultText(result, download) notificationBuilder.run { setTicker(context.getString(tickerId)) - setContentText(contentText) + setContentText(resultText) notificationManager.notify(notifyId, this.build()) } @@ -111,6 +117,18 @@ class DownloadNotificationManager(private val context: Context, private val view ) } + private fun getResultText(result: RemoteOperationResult<*>, download: DownloadFileOperation): String { + return if (result.isSuccess) { + download.file.fileName + } else { + ErrorMessageAdapter.getErrorCauseMessage( + result, + download, + context.resources + ) + } + } + private fun getTickerId(isSuccess: Boolean, needsToUpdateCredentials: Boolean?): Int { return if (needsToUpdateCredentials == true) { R.string.downloader_download_failed_credentials_error @@ -123,20 +141,6 @@ class DownloadNotificationManager(private val context: Context, private val view } } - fun prepareForResult( - downloadResult: RemoteOperationResult<*>, - needsToUpdateCredentials: Boolean - ) { - val tickerId = getTickerId(downloadResult.isSuccess, needsToUpdateCredentials) - - notificationBuilder - .setTicker(context.getString(tickerId)) - .setContentTitle(context.getString(tickerId)) - .setAutoCancel(true) - .setOngoing(false) - .setProgress(0, 0, false) - } - @Suppress("MagicNumber") fun updateDownloadProgressNotification(filePath: String, percent: Int, totalToTransfer: Long) { notificationBuilder.setProgress(100, percent, totalToTransfer < 0) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt index ee0b30e2ad0e..6dc7dde71e2f 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt @@ -27,7 +27,6 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.Build -import androidx.work.WorkManager import com.owncloud.android.datamodel.ReceiverFlag @SuppressLint("UnspecifiedRegisterReceiverFlag") @@ -38,7 +37,3 @@ fun Context.registerBroadcastReceiver(receiver: BroadcastReceiver?, filter: Inte registerReceiver(receiver, filter) } } - -fun Context.isWorkScheduled(tag: String): Boolean { - return WorkManager.getInstance(this).isWorkScheduled(tag) -} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 26a79a3a08c8..51a6da0b5434 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -636,7 +636,7 @@ Resharing is not allowed Uploading files… - Downloading files… + Downloading files… Get source code License From 1c18a3d8404472f7465bd3ad8b81248631338811 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 15:55:08 +0100 Subject: [PATCH 047/189] Move notification manager Signed-off-by: alperozturk --- .../downloader}/DownloadNotificationManager.kt | 2 +- .../com/nextcloud/client/files/downloader/FileDownloadWorker.kt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) rename app/src/main/java/com/nextcloud/client/{notifications/download => files/downloader}/DownloadNotificationManager.kt (99%) diff --git a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt similarity index 99% rename from app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt rename to app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 397e8a5191b9..1457e603fb8e 100644 --- a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -package com.nextcloud.client.notifications.download +package com.nextcloud.client.files.downloader import android.app.Notification import android.app.NotificationManager diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 8b826be235c1..6c82b36a5b99 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -32,7 +32,6 @@ import androidx.work.WorkerParameters import com.google.gson.Gson import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager -import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional import com.nextcloud.model.WorkerState import com.nextcloud.model.WorkerStateLiveData From 01d620f051e0ddb53db4d65f8f17f43721abdd1f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 3 Jan 2024 10:00:36 +0100 Subject: [PATCH 048/189] Simplify worker Signed-off-by: alperozturk --- .../files/downloader/FileDownloadWorker.kt | 28 ++++++------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 6c82b36a5b99..7a19cc5b885f 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -96,7 +96,6 @@ class FileDownloadWorker( private val pendingDownloads = IndexedForest() private var downloadProgressListener = FileDownloadProgressListener() private var currentUser = Optional.empty() - private var startedDownload = false private var storageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null private var user: User? = null @@ -109,7 +108,12 @@ class FileDownloadWorker( notificationManager.init() addAccountUpdateListener() - startDownloadForEachRequest(requestDownloads) + + requestDownloads.forEach { + downloadFile(it) + } + + setIdleWorkerState() Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() @@ -119,11 +123,6 @@ class FileDownloadWorker( } } - override fun onStopped() { - super.onStopped() - setIdleWorkerState() - } - private fun getRequestDownloads(): AbstractList { conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) @@ -190,26 +189,15 @@ class FileDownloadWorker( am.addOnAccountsUpdatedListener(this, null, false) } - private fun startDownloadForEachRequest(requestDownloads: AbstractList) { - val it: Iterator = requestDownloads.iterator() - - while (it.hasNext()) { - val next = it.next() - Log_OC.e(TAG, "Download Key: $next") - downloadFile(next) - } - - startedDownload = false - } - @Suppress("TooGenericExceptionCaught") private fun downloadFile(downloadKey: String) { - startedDownload = true currentDownload = pendingDownloads.get(downloadKey) if (currentDownload == null) { return } + + Log_OC.e(TAG, "FilesDownloadWorker downloading: $downloadKey") setWorkerState(user, currentDownload) val isAccountExist = accountManager.exists(currentDownload?.user?.toPlatformAccount()) From 2da427c04e8c6c5968ff793c7c18ed145391e6a9 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 3 Jan 2024 11:09:15 +0100 Subject: [PATCH 049/189] Add folder download job Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 24 +++- .../files/downloader/FileDownloadWorker.kt | 109 ++++++++++++------ .../client/jobs/BackgroundJobManager.kt | 9 +- .../client/jobs/BackgroundJobManagerImpl.kt | 64 +++++----- .../SynchronizeFolderOperation.java | 18 ++- 5 files changed, 145 insertions(+), 79 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index cc175c2ce7e6..24edd309a2d8 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -29,8 +29,10 @@ import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType +import com.owncloud.android.operations.SynchronizeFolderOperation import com.owncloud.android.utils.MimeTypeUtil import java.io.File +import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject class FileDownloadHelper { @@ -56,12 +58,24 @@ class FileDownloadHelper { } fun isDownloading(user: User?, file: OCFile?): Boolean { - return user != null && file != null && backgroundJobManager.isStartFileDownloadJobScheduled( + if (user == null || file == null) { + return false + } + + return backgroundJobManager.isStartFileDownloadJobScheduled( user, file ) } + private fun isFolderDownloading(folder: OCFile): Boolean { + for ((id, status) in SynchronizeFolderOperation.folderDownloadStatusPair) { + return id == folder.fileId && status + } + + return false + } + fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return backgroundJobManager.cancelFilesDownloadJob(user, file) @@ -117,8 +131,12 @@ class FileDownloadHelper { } } - fun downloadFile(user: User, ocFile: OCFile) { - downloadFile(user, ocFile, downloadType = DownloadType.DOWNLOAD) + fun downloadFolder(folder: OCFile, user: User, files: List) { + backgroundJobManager.startFolderDownloadJob(folder, user, files) + } + + fun downloadFile(user: User, file: OCFile) { + downloadFile(user, file, downloadType = DownloadType.DOWNLOAD) } @Suppress("LongParameterList") diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 7a19cc5b885f..577555680f97 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -26,10 +26,13 @@ import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener import android.app.PendingIntent import android.content.Context +import androidx.core.util.component1 +import androidx.core.util.component2 import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional @@ -43,6 +46,7 @@ import com.owncloud.android.lib.common.OwnCloudAccount import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.OwnCloudClientManagerFactory import com.owncloud.android.lib.common.network.OnDatatransferProgressListener +import com.owncloud.android.lib.common.operations.OperationCancelledException import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode import com.owncloud.android.lib.common.utils.Log_OC @@ -51,6 +55,7 @@ import com.owncloud.android.operations.DownloadType import com.owncloud.android.utils.theme.ViewThemeUtils import java.util.AbstractList import java.util.Vector +import java.util.concurrent.atomic.AtomicBoolean @Suppress("LongParameterList") class FileDownloadWorker( @@ -67,6 +72,7 @@ class FileDownloadWorker( const val USER_NAME = "USER" const val FILE = "FILE" + const val FILES = "FILES" const val BEHAVIOUR = "BEHAVIOUR" const val DOWNLOAD_TYPE = "DOWNLOAD_TYPE" const val ACTIVITY_NAME = "ACTIVITY_NAME" @@ -123,50 +129,47 @@ class FileDownloadWorker( } } + override fun onStopped() { + setIdleWorkerState() + super.onStopped() + } + private fun getRequestDownloads(): AbstractList { + val files = getFiles() + val downloadType = getDownloadType() + setUser() + conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? - val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) - val accountName = inputData.keyValueMap[USER_NAME] as String - user = accountManager.getUser(accountName).get() - val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? - val downloadType = if (downloadTypeAsString != null) { - if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { - DownloadType.DOWNLOAD - } else { - DownloadType.EXPORT - } - } else { - null - } - val behaviour = inputData.keyValueMap[BEHAVIOUR] as String - val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String - val packageName = inputData.keyValueMap[PACKAGE_NAME] as String + val behaviour = inputData.keyValueMap[BEHAVIOUR] as String? ?: "" + val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String? ?: "" + val packageName = inputData.keyValueMap[PACKAGE_NAME] as String? ?: "" val requestedDownloads: AbstractList = Vector() return try { - val operation = DownloadFileOperation( - user, - file, - behaviour, - activityName, - packageName, - context, - downloadType - ) - - operation.addDownloadDataTransferProgressListener(this) - operation.addDownloadDataTransferProgressListener(downloadProgressListener) - val putResult = pendingDownloads.putIfAbsent( - user?.accountName, - file.remotePath, - operation - ) - - if (putResult != null) { - val downloadKey = putResult.first - requestedDownloads.add(downloadKey) - localBroadcastManager.sendBroadcast(intents.newDownloadIntent(operation, putResult.second)) + files.forEach { file -> + val operation = DownloadFileOperation( + user, + file, + behaviour, + activityName, + packageName, + context, + downloadType + ) + + operation.addDownloadDataTransferProgressListener(this) + operation.addDownloadDataTransferProgressListener(downloadProgressListener) + val (downloadKey, linkedToRemotePath) = pendingDownloads.putIfAbsent( + user?.accountName, + file.remotePath, + operation + ) + + if (downloadKey != null) { + requestedDownloads.add(downloadKey) + localBroadcastManager.sendBroadcast(intents.newDownloadIntent(operation, linkedToRemotePath)) + } } requestedDownloads @@ -176,6 +179,36 @@ class FileDownloadWorker( } } + private fun setUser() { + val accountName = inputData.keyValueMap[USER_NAME] as String + user = accountManager.getUser(accountName).get() + } + + private fun getFiles(): List { + val filesJson = inputData.keyValueMap[FILES] as String? + + return if (filesJson != null) { + val ocFileListType = object : TypeToken>() {}.type + gson.fromJson(filesJson, ocFileListType) + } else { + val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) + listOf(file) + } + } + + private fun getDownloadType(): DownloadType? { + val typeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? + return if (typeAsString != null) { + if (typeAsString == DownloadType.DOWNLOAD.toString()) { + DownloadType.DOWNLOAD + } else { + DownloadType.EXPORT + } + } else { + null + } + } + private fun setWorkerState(user: User?, file: DownloadFileOperation?) { WorkerStateLiveData.instance().setWorkState(WorkerState.Download(user, file)) } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index ee338476397f..f60b7f3000fd 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -24,6 +24,7 @@ import androidx.work.ListenableWorker import com.nextcloud.client.account.User import com.owncloud.android.datamodel.OCFile import com.owncloud.android.operations.DownloadType +import java.util.concurrent.atomic.AtomicBoolean /** * This interface allows to control, schedule and monitor all application @@ -152,7 +153,7 @@ interface BackgroundJobManager { @Suppress("LongParameterList") fun startFileDownloadJob( user: User, - ocFile: OCFile, + file: OCFile, behaviour: String, downloadType: DownloadType?, activityName: String, @@ -160,6 +161,12 @@ interface BackgroundJobManager { conflictUploadId: Long? ) + fun startFolderDownloadJob( + folder: OCFile, + user: User, + files: List + ) + fun startPdfGenerateAndUploadWork(user: User, uploadFolder: String, imagePaths: List, pdfPath: String) fun scheduleTestJob() diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 11a2ab765a25..dc2484c5eb41 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -47,6 +47,7 @@ import com.owncloud.android.operations.DownloadType import java.util.Date import java.util.UUID import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicBoolean import kotlin.reflect.KClass /** @@ -108,6 +109,7 @@ internal class BackgroundJobManagerImpl( const val PERIODIC_BACKUP_INTERVAL_MINUTES = 24 * 60L const val DEFAULT_PERIODIC_JOB_INTERVAL_MINUTES = 15L const val DEFAULT_IMMEDIATE_JOB_DELAY_SEC = 3L + private val gson = Gson() private const val KEEP_LOG_MILLIS = 1000 * 60 * 60 * 24 * 3L @@ -510,61 +512,53 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_FILES_UPLOAD + user.accountName, ExistingWorkPolicy.KEEP, request) } - @Suppress("LongParameterList") - private fun getOneTimeDownloadRequest( - user: User, - file: OCFile, - behaviour: String, - downloadType: DownloadType?, - activityName: String, - packageName: String, - conflictUploadId: Long? - ): OneTimeWorkRequest { - val gson = Gson() + private fun startFileDownloadJobTag(user: User, file: OCFile): String { + return JOB_FILES_DOWNLOAD + user.accountName + file.fileId + } + override fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean { + return workManager.isWorkScheduled(startFileDownloadJobTag(user, file)) + } + + override fun startFolderDownloadJob(folder: OCFile, user: User, files: List) { val data = workDataOf( FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FILE to gson.toJson(file), - FileDownloadWorker.BEHAVIOUR to behaviour, - FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), - FileDownloadWorker.ACTIVITY_NAME to activityName, - FileDownloadWorker.PACKAGE_NAME to packageName, - FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId + FileDownloadWorker.FILES to gson.toJson(files), + FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString(), ) - return oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) + val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .setInputData(data) .build() - } - - private fun startFileDownloadJobTag(user: User, file: OCFile): String { - return JOB_FILES_DOWNLOAD + user.accountName + file.fileId - } - override fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean { - return workManager.isWorkScheduled(startFileDownloadJobTag(user, file)) + val tag = startFileDownloadJobTag(user, folder) + workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) } override fun startFileDownloadJob( user: User, - ocFile: OCFile, + file: OCFile, behaviour: String, downloadType: DownloadType?, activityName: String, packageName: String, conflictUploadId: Long? ) { - val request = getOneTimeDownloadRequest( - user, - ocFile, - behaviour, - downloadType, - activityName, - packageName, - conflictUploadId + val data = workDataOf( + FileDownloadWorker.USER_NAME to user.accountName, + FileDownloadWorker.FILE to gson.toJson(file), + FileDownloadWorker.BEHAVIOUR to behaviour, + FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), + FileDownloadWorker.ACTIVITY_NAME to activityName, + FileDownloadWorker.PACKAGE_NAME to packageName, + FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId, ) - val tag = startFileDownloadJobTag(user, ocFile) + val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) + .setInputData(data) + .build() + + val tag = startFileDownloadJobTag(user, file) workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index d6228d3d67bd..7c70b98a9422 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -44,6 +44,7 @@ import java.io.File; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; @@ -438,13 +439,22 @@ private void prepareOpsFromLocalKnowledge() throws OperationCancelledException { } } - private void syncContents() throws OperationCancelledException { startDirectDownloads(); startContentSynchronizations(mFilesToSyncContents); } - private void startDirectDownloads() throws OperationCancelledException { + public static HashMap folderDownloadStatusPair = new HashMap<>(); + + private void startDirectDownloads() { + FileDownloadHelper.Companion.instance().downloadFolder(mLocalFolder, + user, + mFilesForDirectDownload); + + // FIXME cancel request + /* + folderDownloadStatusPair.put(mLocalFolder.getFileId(), true); + for (OCFile file : mFilesForDirectDownload) { synchronized(mCancellationRequested) { if (mCancellationRequested.get()) { @@ -453,6 +463,10 @@ private void startDirectDownloads() throws OperationCancelledException { FileDownloadHelper.Companion.instance().downloadFile(user, file); } } + + folderDownloadStatusPair.replace(mLocalFolder.getFileId(), false); + */ + } /** From dafec345dafd72c3a77e9774b3f535110fdf9b22 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 3 Jan 2024 11:52:30 +0100 Subject: [PATCH 050/189] Fix isDownloadingFolder Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 18 +++++++++++------- .../files/downloader/FileDownloadWorker.kt | 12 +++++++++--- .../client/jobs/BackgroundJobManagerImpl.kt | 2 +- .../operations/SynchronizeFolderOperation.java | 2 -- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 24edd309a2d8..370800b6c97f 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -22,6 +22,7 @@ package com.nextcloud.client.files.downloader import com.nextcloud.client.account.User +import com.nextcloud.client.files.downloader.FileDownloadWorker.Companion.folderDownloadStatusPair import com.nextcloud.client.jobs.BackgroundJobManager import com.owncloud.android.MainApp import com.owncloud.android.datamodel.FileDataStorageManager @@ -29,10 +30,8 @@ import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType -import com.owncloud.android.operations.SynchronizeFolderOperation import com.owncloud.android.utils.MimeTypeUtil import java.io.File -import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject class FileDownloadHelper { @@ -62,14 +61,18 @@ class FileDownloadHelper { return false } - return backgroundJobManager.isStartFileDownloadJobScheduled( - user, - file - ) + return if (file.isFolder) { + isFolderDownloading(file) + } else { + backgroundJobManager.isStartFileDownloadJobScheduled( + user, + file + ) + } } private fun isFolderDownloading(folder: OCFile): Boolean { - for ((id, status) in SynchronizeFolderOperation.folderDownloadStatusPair) { + for ((id, status) in folderDownloadStatusPair) { return id == folder.fileId && status } @@ -132,6 +135,7 @@ class FileDownloadHelper { } fun downloadFolder(folder: OCFile, user: User, files: List) { + folderDownloadStatusPair[folder.fileId] = true backgroundJobManager.startFolderDownloadJob(folder, user, files) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 577555680f97..c319d15f52e1 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -46,7 +46,6 @@ import com.owncloud.android.lib.common.OwnCloudAccount import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.OwnCloudClientManagerFactory import com.owncloud.android.lib.common.network.OnDatatransferProgressListener -import com.owncloud.android.lib.common.operations.OperationCancelledException import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode import com.owncloud.android.lib.common.utils.Log_OC @@ -55,11 +54,10 @@ import com.owncloud.android.operations.DownloadType import com.owncloud.android.utils.theme.ViewThemeUtils import java.util.AbstractList import java.util.Vector -import java.util.concurrent.atomic.AtomicBoolean @Suppress("LongParameterList") class FileDownloadWorker( - private val viewThemeUtils: ViewThemeUtils, + viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, private val uploadsStorageManager: UploadsStorageManager, private var localBroadcastManager: LocalBroadcastManager, @@ -70,6 +68,9 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName + var folderDownloadStatusPair = HashMap() + + const val FOLDER_ID = "FOLDER_ID" const val USER_NAME = "USER" const val FILE = "FILE" const val FILES = "FILES" @@ -214,6 +215,11 @@ class FileDownloadWorker( } private fun setIdleWorkerState() { + val folderId = inputData.keyValueMap[FOLDER_ID] as Long? + folderId?.let { + folderDownloadStatusPair.remove(folderId) + } + WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index dc2484c5eb41..c89cc4176ab1 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -47,7 +47,6 @@ import com.owncloud.android.operations.DownloadType import java.util.Date import java.util.UUID import java.util.concurrent.TimeUnit -import java.util.concurrent.atomic.AtomicBoolean import kotlin.reflect.KClass /** @@ -523,6 +522,7 @@ internal class BackgroundJobManagerImpl( override fun startFolderDownloadJob(folder: OCFile, user: User, files: List) { val data = workDataOf( FileDownloadWorker.USER_NAME to user.accountName, + FileDownloadWorker.FOLDER_ID to folder.fileId, FileDownloadWorker.FILES to gson.toJson(files), FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString(), ) diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index 7c70b98a9422..03e5728868d7 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -44,7 +44,6 @@ import java.io.File; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; @@ -444,7 +443,6 @@ private void syncContents() throws OperationCancelledException { startContentSynchronizations(mFilesToSyncContents); } - public static HashMap folderDownloadStatusPair = new HashMap<>(); private void startDirectDownloads() { FileDownloadHelper.Companion.instance().downloadFolder(mLocalFolder, From c131a1237e69244a152397a007fd3ab10f8908cd Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 3 Jan 2024 14:06:18 +0100 Subject: [PATCH 051/189] Fix cancelAllDownloads Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 5 ++++ .../files/downloader/FileDownloadWorker.kt | 28 +++++++++++++++---- .../client/jobs/BackgroundJobManager.kt | 1 - .../client/jobs/BackgroundJobManagerImpl.kt | 4 +-- .../android/files/services/IndexedForest.java | 6 +++- .../SynchronizeFolderOperation.java | 17 ----------- 6 files changed, 34 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 370800b6c97f..fea0cc61e9a5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -22,7 +22,9 @@ package com.nextcloud.client.files.downloader import com.nextcloud.client.account.User +import com.nextcloud.client.files.downloader.FileDownloadWorker.Companion.cancelAllDownloads import com.nextcloud.client.files.downloader.FileDownloadWorker.Companion.folderDownloadStatusPair +import com.nextcloud.client.files.downloader.FileDownloadWorker.Companion.removePendingDownload import com.nextcloud.client.jobs.BackgroundJobManager import com.owncloud.android.MainApp import com.owncloud.android.datamodel.FileDataStorageManager @@ -81,6 +83,7 @@ class FileDownloadHelper { fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return + cancelAllDownloads() backgroundJobManager.cancelFilesDownloadJob(user, file) } @@ -92,6 +95,8 @@ class FileDownloadHelper { currentDownload.cancel() } + + removePendingDownload(accountName) } fun saveFile( diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index c319d15f52e1..f4dcbb4ac1fe 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -24,6 +24,7 @@ package com.nextcloud.client.files.downloader import android.accounts.Account import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener +import android.app.NotificationManager import android.app.PendingIntent import android.content.Context import androidx.core.util.component1 @@ -38,6 +39,8 @@ import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional import com.nextcloud.model.WorkerState import com.nextcloud.model.WorkerStateLiveData +import com.owncloud.android.MainApp +import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager @@ -57,7 +60,7 @@ import java.util.Vector @Suppress("LongParameterList") class FileDownloadWorker( - viewThemeUtils: ViewThemeUtils, + private val viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, private val uploadsStorageManager: UploadsStorageManager, private var localBroadcastManager: LocalBroadcastManager, @@ -93,6 +96,24 @@ class FileDownloadWorker( fun getDownloadFinishMessage(): String { return FileDownloadWorker::class.java.name + "DOWNLOAD_FINISH" } + + private val pendingDownloads = IndexedForest() + + fun removePendingDownload(accountName: String?) { + pendingDownloads.remove(accountName) + } + + fun cancelAllDownloads() { + pendingDownloads.all.forEach { + it.value.payload?.cancel() + } + + val notificationManager = + MainApp.getAppContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + notificationManager.cancel(R.string.downloader_download_in_progress_ticker) + + pendingDownloads.all.clear() + } } private var currentDownload: DownloadFileOperation? = null @@ -100,7 +121,6 @@ class FileDownloadWorker( private var lastPercent = 0 private val intents = FileDownloadIntents(context) private val notificationManager = DownloadNotificationManager(context, viewThemeUtils) - private val pendingDownloads = IndexedForest() private var downloadProgressListener = FileDownloadProgressListener() private var currentUser = Optional.empty() private var storageManager: FileDataStorageManager? = null @@ -266,10 +286,6 @@ class FileDownloadWorker( } } - private fun removePendingDownload(accountName: String?) { - pendingDownloads.remove(accountName) - } - private fun notifyDownloadStart(download: DownloadFileOperation) { lastPercent = 0 diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index f60b7f3000fd..cc29456db280 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -24,7 +24,6 @@ import androidx.work.ListenableWorker import com.nextcloud.client.account.User import com.owncloud.android.datamodel.OCFile import com.owncloud.android.operations.DownloadType -import java.util.concurrent.atomic.AtomicBoolean /** * This interface allows to control, schedule and monitor all application diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index c89cc4176ab1..735270490574 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -524,7 +524,7 @@ internal class BackgroundJobManagerImpl( FileDownloadWorker.USER_NAME to user.accountName, FileDownloadWorker.FOLDER_ID to folder.fileId, FileDownloadWorker.FILES to gson.toJson(files), - FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString(), + FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() ) val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) @@ -551,7 +551,7 @@ internal class BackgroundJobManagerImpl( FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), FileDownloadWorker.ACTIVITY_NAME to activityName, FileDownloadWorker.PACKAGE_NAME to packageName, - FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId, + FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId ) val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) diff --git a/app/src/main/java/com/owncloud/android/files/services/IndexedForest.java b/app/src/main/java/com/owncloud/android/files/services/IndexedForest.java index 26def14d01d4..3ca41db53297 100644 --- a/app/src/main/java/com/owncloud/android/files/services/IndexedForest.java +++ b/app/src/main/java/com/owncloud/android/files/services/IndexedForest.java @@ -43,8 +43,12 @@ public class IndexedForest { private ConcurrentMap> mMap = new ConcurrentHashMap<>(); + public ConcurrentMap> getAll() { + return mMap; + } + @SuppressWarnings("PMD.ShortClassName") - private class Node { + public class Node { private String mKey; private Node mParent; private Set> mChildren = new HashSet<>(); // TODO be careful with hash() diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index 03e5728868d7..ec65a4cc7e3b 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -448,23 +448,6 @@ private void startDirectDownloads() { FileDownloadHelper.Companion.instance().downloadFolder(mLocalFolder, user, mFilesForDirectDownload); - - // FIXME cancel request - /* - folderDownloadStatusPair.put(mLocalFolder.getFileId(), true); - - for (OCFile file : mFilesForDirectDownload) { - synchronized(mCancellationRequested) { - if (mCancellationRequested.get()) { - throw new OperationCancelledException(); - } - FileDownloadHelper.Companion.instance().downloadFile(user, file); - } - } - - folderDownloadStatusPair.replace(mLocalFolder.getFileId(), false); - */ - } /** From d661dc200189be9b6b1f1ee86cc4d6ecb6a67206 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 3 Jan 2024 16:01:48 +0100 Subject: [PATCH 052/189] Fix worker tag Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 17 +----- .../files/downloader/FileDownloadWorker.kt | 54 +++++++++++-------- .../client/jobs/BackgroundJobManagerImpl.kt | 11 ++-- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index fea0cc61e9a5..c1dce3cac56d 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -22,9 +22,6 @@ package com.nextcloud.client.files.downloader import com.nextcloud.client.account.User -import com.nextcloud.client.files.downloader.FileDownloadWorker.Companion.cancelAllDownloads -import com.nextcloud.client.files.downloader.FileDownloadWorker.Companion.folderDownloadStatusPair -import com.nextcloud.client.files.downloader.FileDownloadWorker.Companion.removePendingDownload import com.nextcloud.client.jobs.BackgroundJobManager import com.owncloud.android.MainApp import com.owncloud.android.datamodel.FileDataStorageManager @@ -64,7 +61,7 @@ class FileDownloadHelper { } return if (file.isFolder) { - isFolderDownloading(file) + FileDownloadWorker.isFolderDownloading(file) } else { backgroundJobManager.isStartFileDownloadJobScheduled( user, @@ -73,17 +70,8 @@ class FileDownloadHelper { } } - private fun isFolderDownloading(folder: OCFile): Boolean { - for ((id, status) in folderDownloadStatusPair) { - return id == folder.fileId && status - } - - return false - } - fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return - cancelAllDownloads() backgroundJobManager.cancelFilesDownloadJob(user, file) } @@ -95,8 +83,6 @@ class FileDownloadHelper { currentDownload.cancel() } - - removePendingDownload(accountName) } fun saveFile( @@ -140,7 +126,6 @@ class FileDownloadHelper { } fun downloadFolder(folder: OCFile, user: User, files: List) { - folderDownloadStatusPair[folder.fileId] = true backgroundJobManager.startFolderDownloadJob(folder, user, files) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index f4dcbb4ac1fe..025f40f6be7d 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -24,7 +24,6 @@ package com.nextcloud.client.files.downloader import android.accounts.Account import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener -import android.app.NotificationManager import android.app.PendingIntent import android.content.Context import androidx.core.util.component1 @@ -39,8 +38,6 @@ import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional import com.nextcloud.model.WorkerState import com.nextcloud.model.WorkerStateLiveData -import com.owncloud.android.MainApp -import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager @@ -71,7 +68,7 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName - var folderDownloadStatusPair = HashMap() + private var folderDownloadStatusPair = HashMap() const val FOLDER_ID = "FOLDER_ID" const val USER_NAME = "USER" @@ -89,6 +86,14 @@ class FileDownloadWorker( const val EXTRA_LINKED_TO_PATH = "LINKED_TO" const val ACCOUNT_NAME = "ACCOUNT_NAME" + fun isFolderDownloading(folder: OCFile): Boolean { + for ((id, status) in folderDownloadStatusPair) { + return id == folder.fileId && status + } + + return false + } + fun getDownloadAddedMessage(): String { return FileDownloadWorker::class.java.name + "DOWNLOAD_ADDED" } @@ -96,24 +101,6 @@ class FileDownloadWorker( fun getDownloadFinishMessage(): String { return FileDownloadWorker::class.java.name + "DOWNLOAD_FINISH" } - - private val pendingDownloads = IndexedForest() - - fun removePendingDownload(accountName: String?) { - pendingDownloads.remove(accountName) - } - - fun cancelAllDownloads() { - pendingDownloads.all.forEach { - it.value.payload?.cancel() - } - - val notificationManager = - MainApp.getAppContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - notificationManager.cancel(R.string.downloader_download_in_progress_ticker) - - pendingDownloads.all.clear() - } } private var currentDownload: DownloadFileOperation? = null @@ -127,6 +114,7 @@ class FileDownloadWorker( private var downloadClient: OwnCloudClient? = null private var user: User? = null private val gson = Gson() + private val pendingDownloads = IndexedForest() @Suppress("TooGenericExceptionCaught") override fun doWork(): Result { @@ -151,7 +139,13 @@ class FileDownloadWorker( } override fun onStopped() { + Log_OC.e(TAG, "FilesDownloadWorker stopped") + + cancelAllDownloads() + notificationManager.dismissDownloadInProgressNotification() + removePendingDownload(currentDownload?.user?.accountName) setIdleWorkerState() + super.onStopped() } @@ -200,6 +194,17 @@ class FileDownloadWorker( } } + private fun removePendingDownload(accountName: String?) { + pendingDownloads.remove(accountName) + } + + private fun cancelAllDownloads() { + pendingDownloads.all.forEach { + it.value.payload?.cancel() + } + pendingDownloads.all.clear() + } + private fun setUser() { val accountName = inputData.keyValueMap[USER_NAME] as String user = accountManager.getUser(accountName).get() @@ -231,6 +236,11 @@ class FileDownloadWorker( } private fun setWorkerState(user: User?, file: DownloadFileOperation?) { + val folderId = inputData.keyValueMap[FOLDER_ID] as Long? + folderId?.let { + folderDownloadStatusPair[folderId] = true + } + WorkerStateLiveData.instance().setWorkState(WorkerState.Download(user, file)) } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 735270490574..caf4e4fd0bf3 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -527,12 +527,15 @@ internal class BackgroundJobManagerImpl( FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() ) + val tag = startFileDownloadJobTag(user, folder) + val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) + .addTag(tag) .setInputData(data) .build() - val tag = startFileDownloadJobTag(user, folder) - workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) + workManager + .enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) } override fun startFileDownloadJob( @@ -554,11 +557,13 @@ internal class BackgroundJobManagerImpl( FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId ) + val tag = startFileDownloadJobTag(user, file) + val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) + .addTag(tag) .setInputData(data) .build() - val tag = startFileDownloadJobTag(user, file) workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) } From ff891aee9cc17a1f97ee94f5413c36dc8ff0bb9b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 3 Jan 2024 16:09:39 +0100 Subject: [PATCH 053/189] Fix code analytics Signed-off-by: alperozturk --- .../com/nextcloud/client/files/downloader/FileDownloadWorker.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 025f40f6be7d..ffd907129fee 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -55,7 +55,7 @@ import com.owncloud.android.utils.theme.ViewThemeUtils import java.util.AbstractList import java.util.Vector -@Suppress("LongParameterList") +@Suppress("LongParameterList", "TooManyFunctions") class FileDownloadWorker( private val viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, From de8e5045bff3233c61fb37ab3b2669ccd2f96487 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 4 Jan 2024 09:22:06 +0100 Subject: [PATCH 054/189] Fix isDownloading Folder Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 12 ++++------- .../files/downloader/FileDownloadWorker.kt | 20 ------------------- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index c1dce3cac56d..9df9157b4b23 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -60,14 +60,10 @@ class FileDownloadHelper { return false } - return if (file.isFolder) { - FileDownloadWorker.isFolderDownloading(file) - } else { - backgroundJobManager.isStartFileDownloadJobScheduled( - user, - file - ) - } + return backgroundJobManager.isStartFileDownloadJobScheduled( + user, + file + ) } fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index ffd907129fee..c6c4eae88ebc 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -68,8 +68,6 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName - private var folderDownloadStatusPair = HashMap() - const val FOLDER_ID = "FOLDER_ID" const val USER_NAME = "USER" const val FILE = "FILE" @@ -86,14 +84,6 @@ class FileDownloadWorker( const val EXTRA_LINKED_TO_PATH = "LINKED_TO" const val ACCOUNT_NAME = "ACCOUNT_NAME" - fun isFolderDownloading(folder: OCFile): Boolean { - for ((id, status) in folderDownloadStatusPair) { - return id == folder.fileId && status - } - - return false - } - fun getDownloadAddedMessage(): String { return FileDownloadWorker::class.java.name + "DOWNLOAD_ADDED" } @@ -236,20 +226,10 @@ class FileDownloadWorker( } private fun setWorkerState(user: User?, file: DownloadFileOperation?) { - val folderId = inputData.keyValueMap[FOLDER_ID] as Long? - folderId?.let { - folderDownloadStatusPair[folderId] = true - } - WorkerStateLiveData.instance().setWorkState(WorkerState.Download(user, file)) } private fun setIdleWorkerState() { - val folderId = inputData.keyValueMap[FOLDER_ID] as Long? - folderId?.let { - folderDownloadStatusPair.remove(folderId) - } - WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } From 09b4cf44b2d4612ebe5ccc0206319ab36845c0cd Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 4 Jan 2024 10:07:12 +0100 Subject: [PATCH 055/189] Better notification for folder download Signed-off-by: alperozturk --- .../downloader/DownloadNotificationManager.kt | 21 ++++++++++++++++ .../files/downloader/FileDownloadWorker.kt | 24 ++++++++++++++++--- .../client/jobs/BackgroundJobManagerImpl.kt | 2 +- .../ui/activity/FileDisplayActivity.java | 1 - app/src/main/res/values/strings.xml | 2 ++ 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 1457e603fb8e..a1083e537019 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -53,6 +53,7 @@ class DownloadNotificationManager(private val context: Context, private val view setContentText(context.resources.getString(R.string.worker_download)) setSmallIcon(R.drawable.notification_icon) setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) } @@ -117,6 +118,26 @@ class DownloadNotificationManager(private val context: Context, private val view ) } + fun notifyForFolderResult(isAnyOperationFailed: Boolean, folderName: String) { + val notifyId = SecureRandom().nextInt() + val message = if (!isAnyOperationFailed) { + context.getString(R.string.downloader_folder_downloaded, folderName) + } else { + context.getString(R.string.downloader_folder_download_failed, folderName) + } + + notificationBuilder.run { + setContentText(message) + notificationManager.notify(notifyId, this.build()) + } + + NotificationUtils.cancelWithDelay( + notificationManager, + notifyId, + 2000 + ) + } + private fun getResultText(result: RemoteOperationResult<*>, download: DownloadFileOperation): String { return if (result.isSuccess) { download.file.fileName diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index c6c4eae88ebc..b89dbfd792ab 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -57,7 +57,7 @@ import java.util.Vector @Suppress("LongParameterList", "TooManyFunctions") class FileDownloadWorker( - private val viewThemeUtils: ViewThemeUtils, + viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, private val uploadsStorageManager: UploadsStorageManager, private var localBroadcastManager: LocalBroadcastManager, @@ -68,7 +68,7 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName - const val FOLDER_ID = "FOLDER_ID" + const val FOLDER = "FOLDER" const val USER_NAME = "USER" const val FILE = "FILE" const val FILES = "FILES" @@ -103,6 +103,8 @@ class FileDownloadWorker( private var storageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null private var user: User? = null + private var folder: OCFile? = null + private var isAnyOperationFailed = true private val gson = Gson() private val pendingDownloads = IndexedForest() @@ -119,6 +121,9 @@ class FileDownloadWorker( } setIdleWorkerState() + folder?.let { + notifyForFolderResult(it) + } Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() @@ -139,11 +144,16 @@ class FileDownloadWorker( super.onStopped() } + private fun notifyForFolderResult(folder: OCFile) { + notificationManager.notifyForFolderResult(isAnyOperationFailed, folder.fileName) + } + private fun getRequestDownloads(): AbstractList { val files = getFiles() val downloadType = getDownloadType() setUser() + folder = gson.fromJson(inputData.keyValueMap[FOLDER] as? String, OCFile::class.java) ?: null conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val behaviour = inputData.keyValueMap[BEHAVIOUR] as String? ?: "" val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String? ?: "" @@ -312,6 +322,10 @@ class FileDownloadWorker( } private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { + result?.let { + isAnyOperationFailed = !it.isSuccess + } + val removeResult = pendingDownloads.removePayload( currentDownload?.user?.accountName, currentDownload?.remotePath @@ -321,11 +335,13 @@ class FileDownloadWorker( currentDownload?.run { notifyDownloadResult(this, downloadResult) + val downloadFinishedIntent = intents.downloadFinishedIntent( this, downloadResult, removeResult.second ) + localBroadcastManager.sendBroadcast(downloadFinishedIntent) } } @@ -353,7 +369,9 @@ class FileDownloadWorker( setContentIntent(intents.detailsIntent(null), PendingIntent.FLAG_IMMUTABLE) } - notifyForResult(downloadResult, download) + if (folder == null) { + notifyForResult(downloadResult, download) + } } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index caf4e4fd0bf3..fafc632deee4 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -522,7 +522,7 @@ internal class BackgroundJobManagerImpl( override fun startFolderDownloadJob(folder: OCFile, user: User, files: List) { val data = workDataOf( FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FOLDER_ID to folder.fileId, + FileDownloadWorker.FOLDER to gson.toJson(folder), FileDownloadWorker.FILES to gson.toJson(files), FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() ) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index d54374c1c4e0..fa290e500d4f 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1585,7 +1585,6 @@ protected ServiceConnection newTransferenceServiceConnection() { return new ListServiceConnection(); } - // FIXME ServiceConnection will not trigger anymore /** * Defines callbacks for service binding, passed to bindService() */ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 51a6da0b5434..2ad28653e254 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -174,6 +174,8 @@ Download failed Could not download %1$s Not downloaded yet + Error occurred while downloading %s folder + %s folder successfully downloaded Download failed, log in again Choose account Switch account From 7bfe1ae164ee31ae01bea6e7f83ad97c56543806 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 4 Jan 2024 10:43:19 +0100 Subject: [PATCH 056/189] Fix code analytics Signed-off-by: alperozturk --- .../downloader/DownloadNotificationManager.kt | 80 +++++++++++-------- .../files/downloader/FileDownloadWorker.kt | 4 +- 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index a1083e537019..eddfed9f3147 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -32,6 +32,7 @@ import androidx.core.app.NotificationCompat import com.nextcloud.client.account.User import com.owncloud.android.R import com.owncloud.android.authentication.AuthenticatorActivity +import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.resources.files.FileUtils import com.owncloud.android.operations.DownloadFileOperation @@ -87,7 +88,7 @@ class DownloadNotificationManager(private val context: Context, private val view downloadResult: RemoteOperationResult<*>, needsToUpdateCredentials: Boolean ) { - val tickerId = getTickerId(downloadResult.isSuccess, needsToUpdateCredentials) + val tickerId = getTickerId(downloadResult.isSuccess, needsToUpdateCredentials, null, null) notificationBuilder .setTicker(context.getString(tickerId)) @@ -98,12 +99,17 @@ class DownloadNotificationManager(private val context: Context, private val view } @Suppress("MagicNumber") - fun notifyForResult(result: RemoteOperationResult<*>, download: DownloadFileOperation) { + fun notifyForResult( + result: RemoteOperationResult<*>?, + download: DownloadFileOperation?, + folder: OCFile?, + isAnyOperationFailed: Boolean? + ) { dismissDownloadInProgressNotification() - val tickerId = getTickerId(result.isSuccess, null) + val tickerId = getTickerId(result?.isSuccess, null, folder, isAnyOperationFailed) val notifyId = SecureRandom().nextInt() - val resultText = getResultText(result, download) + val resultText = getResultText(result, download, folder, isAnyOperationFailed) notificationBuilder.run { setTicker(context.getString(tickerId)) @@ -118,47 +124,55 @@ class DownloadNotificationManager(private val context: Context, private val view ) } - fun notifyForFolderResult(isAnyOperationFailed: Boolean, folderName: String) { - val notifyId = SecureRandom().nextInt() - val message = if (!isAnyOperationFailed) { - context.getString(R.string.downloader_folder_downloaded, folderName) + private fun getResultText( + result: RemoteOperationResult<*>?, + download: DownloadFileOperation?, + folder: OCFile?, + isAnyOperationFailed: Boolean? + ): String { + return folder?.let { + getFolderResultText(isAnyOperationFailed, it) + } ?: if (result?.isSuccess == true) { + download?.file?.fileName ?: "" } else { - context.getString(R.string.downloader_folder_download_failed, folderName) + ErrorMessageAdapter.getErrorCauseMessage(result, download, context.resources) } + } - notificationBuilder.run { - setContentText(message) - notificationManager.notify(notifyId, this.build()) + private fun getFolderResultText(isAnyOperationFailed: Boolean?, folder: OCFile): String { + return if (isAnyOperationFailed == false) { + context.getString(R.string.downloader_folder_downloaded, folder.fileName) + } else { + context.getString(R.string.downloader_folder_download_failed, folder.fileName) } + } - NotificationUtils.cancelWithDelay( - notificationManager, - notifyId, - 2000 - ) + private fun getTickerId( + isSuccess: Boolean?, + needsToUpdateCredentials: Boolean?, + folder: OCFile?, + isAnyOperationFailed: Boolean? + ): Int { + return if (needsToUpdateCredentials == true) { + R.string.downloader_download_failed_credentials_error + } else { + folder?.let { getFolderTickerId(isAnyOperationFailed) } ?: getFileTickerId(isSuccess) + } } - private fun getResultText(result: RemoteOperationResult<*>, download: DownloadFileOperation): String { - return if (result.isSuccess) { - download.file.fileName + private fun getFileTickerId(isSuccess: Boolean?): Int { + return if (isSuccess == true) { + R.string.downloader_download_succeeded_ticker } else { - ErrorMessageAdapter.getErrorCauseMessage( - result, - download, - context.resources - ) + R.string.downloader_download_failed_ticker } } - private fun getTickerId(isSuccess: Boolean, needsToUpdateCredentials: Boolean?): Int { - return if (needsToUpdateCredentials == true) { - R.string.downloader_download_failed_credentials_error + private fun getFolderTickerId(isAnyOperationFailed: Boolean?): Int { + return if (isAnyOperationFailed == false) { + R.string.downloader_folder_downloaded } else { - if (isSuccess) { - R.string.downloader_download_succeeded_ticker - } else { - R.string.downloader_download_failed_ticker - } + R.string.downloader_folder_download_failed } } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index b89dbfd792ab..45a731b92a92 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -145,7 +145,7 @@ class FileDownloadWorker( } private fun notifyForFolderResult(folder: OCFile) { - notificationManager.notifyForFolderResult(isAnyOperationFailed, folder.fileName) + notificationManager.notifyForResult(null, null, folder, isAnyOperationFailed) } private fun getRequestDownloads(): AbstractList { @@ -370,7 +370,7 @@ class FileDownloadWorker( } if (folder == null) { - notifyForResult(downloadResult, download) + notifyForResult(downloadResult, download, null, null) } } } From e32d8adbcf395203cbf542704d732662fa05a36d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 4 Jan 2024 17:00:37 +0100 Subject: [PATCH 057/189] Add capability to track multiple download workers Signed-off-by: alperozturk --- .../files/downloader/FileDownloadWorker.kt | 24 +++++++----- .../client/jobs/BackgroundJobManagerImpl.kt | 5 ++- ...Data.kt => DownloadWorkerStateLiveData.kt} | 24 +++++++++--- .../java/com/nextcloud/model/WorkerState.kt | 5 +-- .../utils/extensions/ContextExtensions.kt | 15 ++++++++ .../ui/activity/FileDisplayActivity.java | 11 +++--- .../ui/activity/ManageAccountsActivity.java | 37 +++++++++++-------- .../android/ui/adapter/GalleryAdapter.kt | 1 + .../android/ui/adapter/OCFileListDelegate.kt | 20 +++++++++- .../ui/preview/PreviewImageActivity.java | 11 +++--- 10 files changed, 102 insertions(+), 51 deletions(-) rename app/src/main/java/com/nextcloud/model/{WorkerStateLiveData.kt => DownloadWorkerStateLiveData.kt} (59%) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 45a731b92a92..8b0f3563ddd6 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -36,8 +36,8 @@ import com.google.gson.reflect.TypeToken import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional -import com.nextcloud.model.WorkerState -import com.nextcloud.model.WorkerStateLiveData +import com.nextcloud.model.DownloadWorkerState +import com.nextcloud.model.DownloadWorkerStateLiveData import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager @@ -68,6 +68,7 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName + const val WORKER_TAG = "WORKER_TAG" const val FOLDER = "FOLDER" const val USER_NAME = "USER" const val FILE = "FILE" @@ -106,6 +107,7 @@ class FileDownloadWorker( private var folder: OCFile? = null private var isAnyOperationFailed = true private val gson = Gson() + private var workerTag: String? = null private val pendingDownloads = IndexedForest() @Suppress("TooGenericExceptionCaught") @@ -144,6 +146,15 @@ class FileDownloadWorker( super.onStopped() } + private fun setWorkerState(user: User?, file: DownloadFileOperation?) { + val worker = DownloadWorkerState(workerTag ?: "", user, file) + DownloadWorkerStateLiveData.instance().addWorker(worker) + } + + private fun setIdleWorkerState() { + DownloadWorkerStateLiveData.instance().removeWorker(workerTag ?: "") + } + private fun notifyForFolderResult(folder: OCFile) { notificationManager.notifyForResult(null, null, folder, isAnyOperationFailed) } @@ -153,6 +164,7 @@ class FileDownloadWorker( val downloadType = getDownloadType() setUser() + workerTag = inputData.keyValueMap[WORKER_TAG] as String? ?: "" folder = gson.fromJson(inputData.keyValueMap[FOLDER] as? String, OCFile::class.java) ?: null conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val behaviour = inputData.keyValueMap[BEHAVIOUR] as String? ?: "" @@ -235,14 +247,6 @@ class FileDownloadWorker( } } - private fun setWorkerState(user: User?, file: DownloadFileOperation?) { - WorkerStateLiveData.instance().setWorkState(WorkerState.Download(user, file)) - } - - private fun setIdleWorkerState() { - WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) - } - private fun addAccountUpdateListener() { val am = AccountManager.get(context) am.addOnAccountsUpdatedListener(this, null, false) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index fafc632deee4..21cc9f7adeda 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -547,7 +547,10 @@ internal class BackgroundJobManagerImpl( packageName: String, conflictUploadId: Long? ) { + val tag = startFileDownloadJobTag(user, file) + val data = workDataOf( + FileDownloadWorker.WORKER_TAG to tag, FileDownloadWorker.USER_NAME to user.accountName, FileDownloadWorker.FILE to gson.toJson(file), FileDownloadWorker.BEHAVIOUR to behaviour, @@ -557,8 +560,6 @@ internal class BackgroundJobManagerImpl( FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId ) - val tag = startFileDownloadJobTag(user, file) - val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .addTag(tag) .setInputData(data) diff --git a/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt b/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt similarity index 59% rename from app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt rename to app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt index 54fd35f4d702..5dcd1ccb687e 100644 --- a/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt +++ b/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt @@ -23,18 +23,30 @@ package com.nextcloud.model import androidx.lifecycle.LiveData -class WorkerStateLiveData private constructor() : LiveData() { +class DownloadWorkerStateLiveData private constructor() : LiveData>() { - fun setWorkState(state: WorkerState) { - postValue(state) + private var workers: ArrayList = arrayListOf() + + 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: WorkerStateLiveData? = null + private var instance: DownloadWorkerStateLiveData? = null - fun instance(): WorkerStateLiveData { + fun instance(): DownloadWorkerStateLiveData { return instance ?: synchronized(this) { - instance ?: WorkerStateLiveData().also { instance = it } + instance ?: DownloadWorkerStateLiveData().also { instance = it } } } } diff --git a/app/src/main/java/com/nextcloud/model/WorkerState.kt b/app/src/main/java/com/nextcloud/model/WorkerState.kt index 5bca9bb62b80..b746154fb60b 100644 --- a/app/src/main/java/com/nextcloud/model/WorkerState.kt +++ b/app/src/main/java/com/nextcloud/model/WorkerState.kt @@ -24,7 +24,4 @@ package com.nextcloud.model import com.nextcloud.client.account.User import com.owncloud.android.operations.DownloadFileOperation -sealed class WorkerState { - object Idle : WorkerState() - class Download(var user: User?, var currentDownload: DownloadFileOperation?) : WorkerState() -} +data class DownloadWorkerState(var tag: String, var user: User?, var currentDownload: DownloadFileOperation?) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt index 6dc7dde71e2f..955d4eb3d024 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt @@ -24,9 +24,11 @@ package com.nextcloud.utils.extensions import android.annotation.SuppressLint import android.content.BroadcastReceiver import android.content.Context +import android.content.ContextWrapper import android.content.Intent import android.content.IntentFilter import android.os.Build +import androidx.lifecycle.LifecycleOwner import com.owncloud.android.datamodel.ReceiverFlag @SuppressLint("UnspecifiedRegisterReceiverFlag") @@ -37,3 +39,16 @@ fun Context.registerBroadcastReceiver(receiver: BroadcastReceiver?, filter: Inte registerReceiver(receiver, filter) } } + +fun Context.lifecycleOwner(): LifecycleOwner? { + var curContext = this + var maxDepth = 20 + while (maxDepth-- > 0 && curContext !is LifecycleOwner) { + curContext = (curContext as ContextWrapper).baseContext + } + return if (curContext is LifecycleOwner) { + curContext + } else { + null + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index fa290e500d4f..e956c3a85ae7 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -73,8 +73,7 @@ import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.client.utils.IntentUtil; import com.nextcloud.java.util.Optional; -import com.nextcloud.model.WorkerState; -import com.nextcloud.model.WorkerStateLiveData; +import com.nextcloud.model.DownloadWorkerStateLiveData; import com.nextcloud.utils.extensions.BundleExtensionsKt; import com.nextcloud.utils.extensions.IntentExtensionsKt; import com.nextcloud.utils.view.FastScrollUtils; @@ -287,7 +286,7 @@ protected void onCreate(Bundle savedInstanceState) { checkStoragePath(); initSyncBroadcastReceiver(); - observeWorkerState(); + observeDownloadWorkerState(); } @SuppressWarnings("unchecked") @@ -1562,9 +1561,9 @@ public boolean isDrawerIndicatorAvailable() { return isRoot(getCurrentDir()); } - private void observeWorkerState() { - WorkerStateLiveData.Companion.instance().observe(this, state -> { - if (state instanceof WorkerState.Download) { + private void observeDownloadWorkerState() { + DownloadWorkerStateLiveData.Companion.instance().observe(this, state -> { + if (!state.isEmpty()) { Log_OC.d(TAG, "Download worker started"); handleDownloadWorkerState(); } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 955c240d0857..9f378374b6eb 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -37,7 +37,6 @@ 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; @@ -45,8 +44,8 @@ import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.onboarding.FirstRunActivity; import com.nextcloud.java.util.Optional; -import com.nextcloud.model.WorkerState; -import com.nextcloud.model.WorkerStateLiveData; +import com.nextcloud.model.DownloadWorkerState; +import com.nextcloud.model.DownloadWorkerStateLiveData; import com.nextcloud.utils.extensions.BundleExtensionsKt; import com.owncloud.android.MainApp; import com.owncloud.android.R; @@ -115,8 +114,7 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap private ArbitraryDataProvider arbitraryDataProvider; private boolean multipleAccountsSupported; - private String workerAccountName; - private DownloadFileOperation workerCurrentDownload; + private final ArrayList downloadWorkerStates = new ArrayList<>(); @Inject BackgroundJobManager backgroundJobManager; @Inject UserAccountManager accountManager; @@ -165,7 +163,7 @@ protected void onCreate(Bundle savedInstanceState) { recyclerView.setAdapter(userListAdapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); initializeComponentGetters(); - observeWorkerState(); + observeDownloadWorkerState(); } @@ -342,7 +340,7 @@ public void run(AccountManagerFuture future) { mUploaderBinder.cancel(accountName); } - FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); + cancelAllDownloadsForAccount(); } User currentUser = getUserAccountManager().getUser(); @@ -410,6 +408,17 @@ protected ServiceConnection newTransferenceServiceConnection() { return new ManageAccountsServiceConnection(); } + private void cancelAllDownloadsForAccount() { + for (DownloadWorkerState workerState : downloadWorkerStates) { + User currentUser = workerState.getUser(); + DownloadFileOperation currentDownload = workerState.getCurrentDownload(); + + if (currentUser != null && currentDownload != null) { + FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(currentUser.getAccountName(), currentDownload); + } + } + } + private void performAccountRemoval(User user) { // disable account in recycler view for (int i = 0; i < userListAdapter.getItemCount(); i++) { @@ -432,8 +441,7 @@ private void performAccountRemoval(User user) { mUploaderBinder.cancel(user); } - FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); - + cancelAllDownloadsForAccount(); backgroundJobManager.startAccountRemovalJob(user.getAccountName(), false); // immediately select a new account @@ -517,13 +525,10 @@ public void onOptionItemClicked(User user, View view) { } } - private void observeWorkerState() { - WorkerStateLiveData.Companion.instance().observe(this, state -> { - if (state instanceof WorkerState.Download) { - Log_OC.d(TAG, "Download worker started"); - workerAccountName = ((WorkerState.Download) state).getUser().getAccountName(); - workerCurrentDownload = ((WorkerState.Download) state).getCurrentDownload(); - } + private void observeDownloadWorkerState() { + DownloadWorkerStateLiveData.Companion.instance().observe(this, state -> { + Log_OC.d(TAG, "Download worker started"); + downloadWorkerStates.addAll(state); }); } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt index df1e1669e88f..1c8e426f9fc6 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt @@ -31,6 +31,7 @@ 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 diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index e4fef4e2999b..7a204b9b91bd 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -34,7 +34,9 @@ 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.nextcloud.utils.extensions.lifecycleOwner import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -74,6 +76,11 @@ class OCFileListDelegate( fun setHighlightedItem(highlightedItem: OCFile?) { this.highlightedItem = highlightedItem } + private var isDownloading = false + + init { + isDownloading() + } fun isCheckedFile(file: OCFile): Boolean { return checkedFiles.contains(file) @@ -339,13 +346,24 @@ class OCFileListDelegate( } } + // FIXME + private fun isDownloading() { + context.lifecycleOwner()?.let { + DownloadWorkerStateLiveData.instance().observe(it) { downloadWorkerStates -> + downloadWorkerStates.forEach { state -> + isDownloading = FileDownloadHelper.instance().isDownloading(user, state.currentDownload?.file) + } + } + } + } + private fun showLocalFileIndicator(file: OCFile, gridViewHolder: ListGridImageViewHolder) { val operationsServiceBinder = transferServiceGetter.operationsServiceBinder val fileUploaderBinder = transferServiceGetter.fileUploaderBinder val icon: Int? = when { operationsServiceBinder?.isSynchronizing(user, file) == true || - FileDownloadHelper.instance().isDownloading(user, file) || + isDownloading || fileUploaderBinder?.isUploading(user, file) == true -> { // synchronizing, downloading or uploading R.drawable.ic_synchronizing diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 80c07b03d7a7..dcff8e8d4b14 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -41,8 +41,7 @@ import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.java.util.Optional; -import com.nextcloud.model.WorkerState; -import com.nextcloud.model.WorkerStateLiveData; +import com.nextcloud.model.DownloadWorkerStateLiveData; import com.nextcloud.utils.extensions.IntentExtensionsKt; import com.owncloud.android.MainApp; import com.owncloud.android.R; @@ -152,7 +151,7 @@ protected void onCreate(Bundle savedInstanceState) { mRequestWaitingForBinder = false; } - observeWorkerState(); + observeDownloadWorkerState(); } public void toggleActionBarVisibility(boolean hide) { @@ -306,9 +305,9 @@ private void onSynchronizeFileOperationFinish(RemoteOperationResult result) { } } - private void observeWorkerState() { - WorkerStateLiveData.Companion.instance().observe(this, state -> { - if (state instanceof WorkerState.Download) { + private void observeDownloadWorkerState() { + DownloadWorkerStateLiveData.Companion.instance().observe(this, state -> { + if (!state.isEmpty()) { Log_OC.d(TAG, "Download worker started"); isDownloadWorkStarted = true; From b2b94ff4cc0ce034b3ab6f4bdda17435a54c9ff2 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 10:22:36 +0100 Subject: [PATCH 058/189] Fix serializable data limit crash Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 11 ++-- .../files/downloader/FileDownloadWorker.kt | 52 +++++++++++++------ .../client/jobs/BackgroundJobManager.kt | 10 ++-- .../client/jobs/BackgroundJobManagerImpl.kt | 26 +++++----- .../model/DownloadWorkerStateLiveData.kt | 18 +++++++ .../java/com/nextcloud/model/WorkerState.kt | 3 +- .../utils/extensions/ContextExtensions.kt | 15 ------ .../ui/activity/ManageAccountsActivity.java | 10 ++-- .../android/ui/adapter/OCFileListDelegate.kt | 19 +------ 9 files changed, 87 insertions(+), 77 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 9df9157b4b23..247b24249be1 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -62,19 +62,19 @@ class FileDownloadHelper { return backgroundJobManager.isStartFileDownloadJobScheduled( user, - file + file.remotePath ) } fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return - backgroundJobManager.cancelFilesDownloadJob(user, file) + backgroundJobManager.cancelFilesDownloadJob(user, file.remotePath) } fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation) { if (currentDownload.user.nameEquals(accountName)) { currentDownload.file?.let { file -> - backgroundJobManager.cancelFilesDownloadJob(currentDownload.user, file) + backgroundJobManager.cancelFilesDownloadJob(currentDownload.user, file.remotePath) } currentDownload.cancel() @@ -122,7 +122,8 @@ class FileDownloadHelper { } fun downloadFolder(folder: OCFile, user: User, files: List) { - backgroundJobManager.startFolderDownloadJob(folder, user, files) + val filesPath = files.map { it.remotePath } + backgroundJobManager.startFolderDownloadJob(folder.remotePath, user, filesPath) } fun downloadFile(user: User, file: OCFile) { @@ -141,7 +142,7 @@ class FileDownloadHelper { ) { backgroundJobManager.startFileDownloadJob( user, - ocFile, + ocFile.remotePath, behaviour, downloadType, activityName, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 8b0f3563ddd6..b98ceee8c5e9 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -31,8 +31,6 @@ import androidx.core.util.component2 import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters -import com.google.gson.Gson -import com.google.gson.reflect.TypeToken import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional @@ -68,11 +66,12 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName + const val FILES_SEPARATOR = "," const val WORKER_TAG = "WORKER_TAG" - const val FOLDER = "FOLDER" + const val FOLDER_PATH = "FOLDER_PATH" const val USER_NAME = "USER" - const val FILE = "FILE" - const val FILES = "FILES" + const val FILE_PATH = "FILE_PATH" + const val FILES_PATH = "FILES_PATH" const val BEHAVIOUR = "BEHAVIOUR" const val DOWNLOAD_TYPE = "DOWNLOAD_TYPE" const val ACTIVITY_NAME = "ACTIVITY_NAME" @@ -102,11 +101,11 @@ class FileDownloadWorker( private var downloadProgressListener = FileDownloadProgressListener() private var currentUser = Optional.empty() private var storageManager: FileDataStorageManager? = null + private var fileDataStorageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null private var user: User? = null private var folder: OCFile? = null private var isAnyOperationFailed = true - private val gson = Gson() private var workerTag: String? = null private val pendingDownloads = IndexedForest() @@ -118,6 +117,7 @@ class FileDownloadWorker( notificationManager.init() addAccountUpdateListener() + setWorkerState(user) requestDownloads.forEach { downloadFile(it) } @@ -146,8 +146,8 @@ class FileDownloadWorker( super.onStopped() } - private fun setWorkerState(user: User?, file: DownloadFileOperation?) { - val worker = DownloadWorkerState(workerTag ?: "", user, file) + private fun setWorkerState(user: User?) { + val worker = DownloadWorkerState(workerTag ?: "", user, pendingDownloads) DownloadWorkerStateLiveData.instance().addWorker(worker) } @@ -160,13 +160,14 @@ class FileDownloadWorker( } private fun getRequestDownloads(): AbstractList { + setUser() + setFolder() val files = getFiles() val downloadType = getDownloadType() - setUser() workerTag = inputData.keyValueMap[WORKER_TAG] as String? ?: "" - folder = gson.fromJson(inputData.keyValueMap[FOLDER] as? String, OCFile::class.java) ?: null conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? + val behaviour = inputData.keyValueMap[BEHAVIOUR] as String? ?: "" val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String? ?: "" val packageName = inputData.keyValueMap[PACKAGE_NAME] as String? ?: "" @@ -220,18 +221,36 @@ class FileDownloadWorker( private fun setUser() { val accountName = inputData.keyValueMap[USER_NAME] as String user = accountManager.getUser(accountName).get() + fileDataStorageManager = FileDataStorageManager(user, context.contentResolver) + } + + private fun setFolder() { + val folderPath = inputData.keyValueMap[FOLDER_PATH] as? String? + if (folderPath != null) { + folder = storageManager?.getFileByEncryptedRemotePath(folderPath) + } } private fun getFiles(): List { - val filesJson = inputData.keyValueMap[FILES] as String? + val result = arrayListOf() - return if (filesJson != null) { - val ocFileListType = object : TypeToken>() {}.type - gson.fromJson(filesJson, ocFileListType) + val filesPath = inputData.keyValueMap[FILES_PATH] as String? + val filesPathList = filesPath?.split(FILES_SEPARATOR) + + if (filesPathList != null) { + filesPathList.forEach { + fileDataStorageManager?.getFileByEncryptedRemotePath(it)?.let { file -> + result.add(file) + } + } } else { - val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) - listOf(file) + val remotePath = inputData.keyValueMap[FILE_PATH] as String + fileDataStorageManager?.getFileByEncryptedRemotePath(remotePath)?.let { file -> + result.add(file) + } } + + return result } private fun getDownloadType(): DownloadType? { @@ -261,7 +280,6 @@ class FileDownloadWorker( } Log_OC.e(TAG, "FilesDownloadWorker downloading: $downloadKey") - setWorkerState(user, currentDownload) val isAccountExist = accountManager.exists(currentDownload?.user?.toPlatformAccount()) if (!isAccountExist) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index cc29456db280..4555417de992 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -145,14 +145,14 @@ interface BackgroundJobManager { fun getFileUploads(user: User): LiveData> fun cancelFilesUploadJob(user: User) - fun cancelFilesDownloadJob(user: User, file: OCFile) + fun cancelFilesDownloadJob(user: User, path: String) - fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean + fun isStartFileDownloadJobScheduled(user: User, path: String): Boolean @Suppress("LongParameterList") fun startFileDownloadJob( user: User, - file: OCFile, + filePath: String, behaviour: String, downloadType: DownloadType?, activityName: String, @@ -161,9 +161,9 @@ interface BackgroundJobManager { ) fun startFolderDownloadJob( - folder: OCFile, + folderPath: String, user: User, - files: List + filesPath: List ) fun startPdfGenerateAndUploadWork(user: User, uploadFolder: String, imagePaths: List, pdfPath: String) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 21cc9f7adeda..1540cdd4b95f 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -511,23 +511,23 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_FILES_UPLOAD + user.accountName, ExistingWorkPolicy.KEEP, request) } - private fun startFileDownloadJobTag(user: User, file: OCFile): String { - return JOB_FILES_DOWNLOAD + user.accountName + file.fileId + private fun startFileDownloadJobTag(user: User, path: String): String { + return JOB_FILES_DOWNLOAD + user.accountName + path } - override fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean { - return workManager.isWorkScheduled(startFileDownloadJobTag(user, file)) + override fun isStartFileDownloadJobScheduled(user: User, path: String): Boolean { + return workManager.isWorkScheduled(startFileDownloadJobTag(user, path)) } - override fun startFolderDownloadJob(folder: OCFile, user: User, files: List) { + override fun startFolderDownloadJob(folderPath: String, user: User, filesPath: List) { val data = workDataOf( FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FOLDER to gson.toJson(folder), - FileDownloadWorker.FILES to gson.toJson(files), + FileDownloadWorker.FOLDER_PATH to folderPath, + FileDownloadWorker.FILES_PATH to filesPath.joinToString(FileDownloadWorker.FILES_SEPARATOR), FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() ) - val tag = startFileDownloadJobTag(user, folder) + val tag = startFileDownloadJobTag(user, folderPath) val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .addTag(tag) @@ -540,19 +540,19 @@ internal class BackgroundJobManagerImpl( override fun startFileDownloadJob( user: User, - file: OCFile, + filePath: String, behaviour: String, downloadType: DownloadType?, activityName: String, packageName: String, conflictUploadId: Long? ) { - val tag = startFileDownloadJobTag(user, file) + val tag = startFileDownloadJobTag(user, filePath) val data = workDataOf( FileDownloadWorker.WORKER_TAG to tag, FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FILE to gson.toJson(file), + FileDownloadWorker.FILE_PATH to filePath, FileDownloadWorker.BEHAVIOUR to behaviour, FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), FileDownloadWorker.ACTIVITY_NAME to activityName, @@ -577,8 +577,8 @@ internal class BackgroundJobManagerImpl( workManager.cancelJob(JOB_FILES_UPLOAD, user) } - override fun cancelFilesDownloadJob(user: User, file: OCFile) { - workManager.cancelAllWorkByTag(startFileDownloadJobTag(user, file)) + override fun cancelFilesDownloadJob(user: User, path: String) { + workManager.cancelAllWorkByTag(startFileDownloadJobTag(user, path)) } override fun startPdfGenerateAndUploadWork( diff --git a/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt b/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt index 5dcd1ccb687e..8e1672727723 100644 --- a/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt +++ b/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt @@ -22,11 +22,29 @@ 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>() { private var workers: ArrayList = 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) { diff --git a/app/src/main/java/com/nextcloud/model/WorkerState.kt b/app/src/main/java/com/nextcloud/model/WorkerState.kt index b746154fb60b..ebe2723c1239 100644 --- a/app/src/main/java/com/nextcloud/model/WorkerState.kt +++ b/app/src/main/java/com/nextcloud/model/WorkerState.kt @@ -22,6 +22,7 @@ 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 currentDownload: DownloadFileOperation?) +data class DownloadWorkerState(var tag: String, var user: User?, var pendingDownloads: IndexedForest?) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt index 955d4eb3d024..6dc7dde71e2f 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt @@ -24,11 +24,9 @@ package com.nextcloud.utils.extensions import android.annotation.SuppressLint import android.content.BroadcastReceiver import android.content.Context -import android.content.ContextWrapper import android.content.Intent import android.content.IntentFilter import android.os.Build -import androidx.lifecycle.LifecycleOwner import com.owncloud.android.datamodel.ReceiverFlag @SuppressLint("UnspecifiedRegisterReceiverFlag") @@ -39,16 +37,3 @@ fun Context.registerBroadcastReceiver(receiver: BroadcastReceiver?, filter: Inte registerReceiver(receiver, filter) } } - -fun Context.lifecycleOwner(): LifecycleOwner? { - var curContext = this - var maxDepth = 20 - while (maxDepth-- > 0 && curContext !is LifecycleOwner) { - curContext = (curContext as ContextWrapper).baseContext - } - return if (curContext is LifecycleOwner) { - curContext - } else { - null - } -} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 9f378374b6eb..88b1a9c0f3ba 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -54,6 +54,7 @@ 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; @@ -411,10 +412,13 @@ protected ServiceConnection newTransferenceServiceConnection() { private void cancelAllDownloadsForAccount() { for (DownloadWorkerState workerState : downloadWorkerStates) { User currentUser = workerState.getUser(); - DownloadFileOperation currentDownload = workerState.getCurrentDownload(); + IndexedForest pendingDownloads = workerState.getPendingDownloads(); - if (currentUser != null && currentDownload != null) { - FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(currentUser.getAccountName(), currentDownload); + if (currentUser != null && pendingDownloads != null) { + pendingDownloads.getAll().values().forEach((value) -> { + DownloadFileOperation operation = value.getPayload(); + FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(currentUser.getAccountName(), operation); + }); } } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 7a204b9b91bd..c2dcac7d92c2 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -36,7 +36,6 @@ 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.nextcloud.utils.extensions.lifecycleOwner import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -76,11 +75,6 @@ class OCFileListDelegate( fun setHighlightedItem(highlightedItem: OCFile?) { this.highlightedItem = highlightedItem } - private var isDownloading = false - - init { - isDownloading() - } fun isCheckedFile(file: OCFile): Boolean { return checkedFiles.contains(file) @@ -346,24 +340,13 @@ class OCFileListDelegate( } } - // FIXME - private fun isDownloading() { - context.lifecycleOwner()?.let { - DownloadWorkerStateLiveData.instance().observe(it) { downloadWorkerStates -> - downloadWorkerStates.forEach { state -> - isDownloading = FileDownloadHelper.instance().isDownloading(user, state.currentDownload?.file) - } - } - } - } - private fun showLocalFileIndicator(file: OCFile, gridViewHolder: ListGridImageViewHolder) { val operationsServiceBinder = transferServiceGetter.operationsServiceBinder val fileUploaderBinder = transferServiceGetter.fileUploaderBinder val icon: Int? = when { operationsServiceBinder?.isSynchronizing(user, file) == true || - isDownloading || + DownloadWorkerStateLiveData.instance().isDownloading(user, file) || fileUploaderBinder?.isUploading(user, file) == true -> { // synchronizing, downloading or uploading R.drawable.ic_synchronizing From 2038c7ce59f7f3e648d3b5bb053b133ddfbbed59 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 10:36:51 +0100 Subject: [PATCH 059/189] Fix file sync icon Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 10 +++---- .../client/jobs/BackgroundJobManager.kt | 8 +++--- .../client/jobs/BackgroundJobManagerImpl.kt | 27 +++++++++---------- .../model/DownloadWorkerStateLiveData.kt | 2 +- .../android/ui/adapter/OCFileListDelegate.kt | 8 +++++- 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 247b24249be1..24a5b4df7ae5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -62,19 +62,19 @@ class FileDownloadHelper { return backgroundJobManager.isStartFileDownloadJobScheduled( user, - file.remotePath + file ) } fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return - backgroundJobManager.cancelFilesDownloadJob(user, file.remotePath) + backgroundJobManager.cancelFilesDownloadJob(user, file) } fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation) { if (currentDownload.user.nameEquals(accountName)) { currentDownload.file?.let { file -> - backgroundJobManager.cancelFilesDownloadJob(currentDownload.user, file.remotePath) + backgroundJobManager.cancelFilesDownloadJob(currentDownload.user, file) } currentDownload.cancel() @@ -123,7 +123,7 @@ class FileDownloadHelper { fun downloadFolder(folder: OCFile, user: User, files: List) { val filesPath = files.map { it.remotePath } - backgroundJobManager.startFolderDownloadJob(folder.remotePath, user, filesPath) + backgroundJobManager.startFolderDownloadJob(folder, user, filesPath) } fun downloadFile(user: User, file: OCFile) { @@ -142,7 +142,7 @@ class FileDownloadHelper { ) { backgroundJobManager.startFileDownloadJob( user, - ocFile.remotePath, + ocFile, behaviour, downloadType, activityName, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 4555417de992..0a37bc0585da 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -145,14 +145,14 @@ interface BackgroundJobManager { fun getFileUploads(user: User): LiveData> fun cancelFilesUploadJob(user: User) - fun cancelFilesDownloadJob(user: User, path: String) + fun cancelFilesDownloadJob(user: User, ocFile: OCFile) - fun isStartFileDownloadJobScheduled(user: User, path: String): Boolean + fun isStartFileDownloadJobScheduled(user: User, ocFile: OCFile): Boolean @Suppress("LongParameterList") fun startFileDownloadJob( user: User, - filePath: String, + file: OCFile, behaviour: String, downloadType: DownloadType?, activityName: String, @@ -161,7 +161,7 @@ interface BackgroundJobManager { ) fun startFolderDownloadJob( - folderPath: String, + folder: OCFile, user: User, filesPath: List ) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 1540cdd4b95f..f469376aac78 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -42,6 +42,7 @@ 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 @@ -108,7 +109,6 @@ internal class BackgroundJobManagerImpl( const val PERIODIC_BACKUP_INTERVAL_MINUTES = 24 * 60L const val DEFAULT_PERIODIC_JOB_INTERVAL_MINUTES = 15L const val DEFAULT_IMMEDIATE_JOB_DELAY_SEC = 3L - private val gson = Gson() private const val KEEP_LOG_MILLIS = 1000 * 60 * 60 * 24 * 3L @@ -500,7 +500,6 @@ internal class BackgroundJobManagerImpl( workManager.enqueue(request) } - override fun startFilesUploadJob(user: User) { val data = workDataOf(FilesUploadWorker.ACCOUNT to user.accountName) @@ -511,23 +510,23 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_FILES_UPLOAD + user.accountName, ExistingWorkPolicy.KEEP, request) } - private fun startFileDownloadJobTag(user: User, path: String): String { - return JOB_FILES_DOWNLOAD + user.accountName + path + private fun startFileDownloadJobTag(user: User, ocFile: OCFile): String { + return JOB_FILES_DOWNLOAD + user.accountName + ocFile.fileId } - override fun isStartFileDownloadJobScheduled(user: User, path: String): Boolean { - return workManager.isWorkScheduled(startFileDownloadJobTag(user, path)) + override fun isStartFileDownloadJobScheduled(user: User, ocFile: OCFile): Boolean { + return workManager.isWorkScheduled(startFileDownloadJobTag(user, ocFile)) } - override fun startFolderDownloadJob(folderPath: String, user: User, filesPath: List) { + override fun startFolderDownloadJob(folder: OCFile, user: User, filesPath: List) { val data = workDataOf( FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FOLDER_PATH to folderPath, + FileDownloadWorker.FOLDER_PATH to folder.remotePath, FileDownloadWorker.FILES_PATH to filesPath.joinToString(FileDownloadWorker.FILES_SEPARATOR), FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() ) - val tag = startFileDownloadJobTag(user, folderPath) + val tag = startFileDownloadJobTag(user, folder) val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .addTag(tag) @@ -540,19 +539,19 @@ internal class BackgroundJobManagerImpl( override fun startFileDownloadJob( user: User, - filePath: String, + file: OCFile, behaviour: String, downloadType: DownloadType?, activityName: String, packageName: String, conflictUploadId: Long? ) { - val tag = startFileDownloadJobTag(user, filePath) + val tag = startFileDownloadJobTag(user, file) val data = workDataOf( FileDownloadWorker.WORKER_TAG to tag, FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FILE_PATH to filePath, + FileDownloadWorker.FILE_PATH to file.remotePath, FileDownloadWorker.BEHAVIOUR to behaviour, FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), FileDownloadWorker.ACTIVITY_NAME to activityName, @@ -577,8 +576,8 @@ internal class BackgroundJobManagerImpl( workManager.cancelJob(JOB_FILES_UPLOAD, user) } - override fun cancelFilesDownloadJob(user: User, path: String) { - workManager.cancelAllWorkByTag(startFileDownloadJobTag(user, path)) + override fun cancelFilesDownloadJob(user: User, ocFile: OCFile) { + workManager.cancelAllWorkByTag(startFileDownloadJobTag(user, ocFile)) } override fun startPdfGenerateAndUploadWork( diff --git a/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt b/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt index 8e1672727723..a3a97921c1d8 100644 --- a/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt +++ b/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt @@ -25,7 +25,7 @@ import androidx.lifecycle.LiveData import com.nextcloud.client.account.User import com.owncloud.android.datamodel.OCFile -class DownloadWorkerStateLiveData private constructor() : LiveData>() { +class DownloadWorkerStateLiveData private constructor(): LiveData>() { private var workers: ArrayList = arrayListOf() diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index c2dcac7d92c2..1ceecc16f172 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -344,9 +344,15 @@ 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 || - DownloadWorkerStateLiveData.instance().isDownloading(user, file) || + isDownloading || fileUploaderBinder?.isUploading(user, file) == true -> { // synchronizing, downloading or uploading R.drawable.ic_synchronizing From 742f01259db3b4aac3d1abafe456e00bfe6500c9 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 11:06:04 +0100 Subject: [PATCH 060/189] Fix tracking current download status Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 2 +- .../files/downloader/FileDownloadWorker.kt | 25 ++++--- .../client/jobs/BackgroundJobManagerImpl.kt | 3 - .../model/DownloadWorkerStateLiveData.kt | 71 ------------------- .../java/com/nextcloud/model/WorkerState.kt | 6 +- .../nextcloud/model/WorkerStateLiveData.kt | 41 +++++++++++ .../ui/activity/FileDisplayActivity.java | 7 +- .../ui/activity/ManageAccountsActivity.java | 41 +++++------ .../android/ui/adapter/GalleryAdapter.kt | 1 - .../android/ui/adapter/OCFileListDelegate.kt | 16 ++--- .../ui/preview/PreviewImageActivity.java | 7 +- 11 files changed, 92 insertions(+), 128 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt create mode 100644 app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 24a5b4df7ae5..e599755727ef 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -63,7 +63,7 @@ class FileDownloadHelper { return backgroundJobManager.isStartFileDownloadJobScheduled( user, file - ) + ) || FileDownloadWorker.isDownloading(user, file) } fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index b98ceee8c5e9..8705a6a3b2f5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -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() 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() @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() { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index f469376aac78..8b4c2ef6ff48 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -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, diff --git a/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt b/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt deleted file mode 100644 index a3a97921c1d8..000000000000 --- a/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt +++ /dev/null @@ -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 . - */ - -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>() { - - private var workers: ArrayList = 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 } - } - } - } -} diff --git a/app/src/main/java/com/nextcloud/model/WorkerState.kt b/app/src/main/java/com/nextcloud/model/WorkerState.kt index ebe2723c1239..5bca9bb62b80 100644 --- a/app/src/main/java/com/nextcloud/model/WorkerState.kt +++ b/app/src/main/java/com/nextcloud/model/WorkerState.kt @@ -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?) +sealed class WorkerState { + object Idle : WorkerState() + class Download(var user: User?, var currentDownload: DownloadFileOperation?) : WorkerState() +} diff --git a/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt b/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt new file mode 100644 index 000000000000..54fd35f4d702 --- /dev/null +++ b/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt @@ -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 . + */ + +package com.nextcloud.model + +import androidx.lifecycle.LiveData + +class WorkerStateLiveData private constructor() : LiveData() { + + 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 } + } + } + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index e956c3a85ae7..43d7a3a740a4 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -73,7 +73,8 @@ 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 boolean isDrawerIndicatorAvailable() { } 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(); } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 88b1a9c0f3ba..955c240d0857 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -37,6 +37,7 @@ 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.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.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 downloadWorkerStates = new ArrayList<>(); + private String workerAccountName; + private DownloadFileOperation workerCurrentDownload; @Inject BackgroundJobManager backgroundJobManager; @Inject UserAccountManager accountManager; @@ -164,7 +165,7 @@ protected void onCreate(Bundle savedInstanceState) { recyclerView.setAdapter(userListAdapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); initializeComponentGetters(); - observeDownloadWorkerState(); + observeWorkerState(); } @@ -341,7 +342,7 @@ public void run(AccountManagerFuture future) { mUploaderBinder.cancel(accountName); } - cancelAllDownloadsForAccount(); + FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); } User currentUser = getUserAccountManager().getUser(); @@ -409,20 +410,6 @@ protected ServiceConnection newTransferenceServiceConnection() { return new ManageAccountsServiceConnection(); } - private void cancelAllDownloadsForAccount() { - for (DownloadWorkerState workerState : downloadWorkerStates) { - User currentUser = workerState.getUser(); - IndexedForest 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 @@ private void performAccountRemoval(User user) { 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 void onOptionItemClicked(User user, View view) { } } - private void observeDownloadWorkerState() { - DownloadWorkerStateLiveData.Companion.instance().observe(this, state -> { - Log_OC.d(TAG, "Download worker started"); - downloadWorkerStates.addAll(state); + private void observeWorkerState() { + WorkerStateLiveData.Companion.instance().observe(this, state -> { + if (state instanceof WorkerState.Download) { + Log_OC.d(TAG, "Download worker started"); + workerAccountName = ((WorkerState.Download) state).getUser().getAccountName(); + workerCurrentDownload = ((WorkerState.Download) state).getCurrentDownload(); + } }); } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt index 1c8e426f9fc6..df1e1669e88f 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt @@ -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 diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 1ceecc16f172..82413ce9076b 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -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 { diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index dcff8e8d4b14..ae8d07ec2046 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -41,7 +41,8 @@ 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 @@ private void onSynchronizeFileOperationFinish(RemoteOperationResult result) { } 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; From db1d58205c29d93143f852ba84c69d7585f8800f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 11:23:47 +0100 Subject: [PATCH 061/189] Fix tracking current download status Signed-off-by: alperozturk --- .../files/downloader/DownloadNotificationManager.kt | 4 ++++ .../client/files/downloader/FileDownloadWorker.kt | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index eddfed9f3147..176bd9ac719f 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -196,6 +196,10 @@ class DownloadNotificationManager(private val context: Context, private val view notificationManager.cancel(R.string.downloader_download_in_progress_ticker) } + fun dismissAll() { + notificationManager.cancelAll() + } + fun setCredentialContentIntent(user: User) { val intent = Intent(context, AuthenticatorActivity::class.java).apply { putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 8705a6a3b2f5..f38273488f55 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -128,11 +128,11 @@ class FileDownloadWorker( downloadFile(it) } - setIdleWorkerState() folder?.let { notifyForFolderResult(it) } + setIdleWorkerState() Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() } catch (t: Throwable) { @@ -144,9 +144,9 @@ class FileDownloadWorker( override fun onStopped() { Log_OC.e(TAG, "FilesDownloadWorker stopped") - cancelAllDownloads() - notificationManager.dismissDownloadInProgressNotification() removePendingDownload(currentDownload?.user?.accountName) + cancelAllDownloads() + notificationManager.dismissAll() setIdleWorkerState() super.onStopped() @@ -157,6 +157,8 @@ class FileDownloadWorker( } private fun setIdleWorkerState() { + pendingDownloads.all.clear() + currentDownload = null WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } @@ -219,8 +221,6 @@ class FileDownloadWorker( pendingDownloads.all.forEach { it.value.payload?.cancel() } - pendingDownloads.all.clear() - currentDownload = null } private fun setUser() { From 3ccec8e5fdf6056be489e75568a705cc667b982c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 11:33:23 +0100 Subject: [PATCH 062/189] Add dismissAll notification Signed-off-by: alperozturk --- .../client/files/downloader/DownloadNotificationManager.kt | 6 +++++- .../nextcloud/client/files/downloader/FileDownloadWorker.kt | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 176bd9ac719f..83917d883a37 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -28,6 +28,8 @@ import android.content.Context import android.content.Intent import android.graphics.BitmapFactory import android.os.Build +import android.os.Handler +import android.os.Looper import androidx.core.app.NotificationCompat import com.nextcloud.client.account.User import com.owncloud.android.R @@ -197,7 +199,9 @@ class DownloadNotificationManager(private val context: Context, private val view } fun dismissAll() { - notificationManager.cancelAll() + Handler(Looper.getMainLooper()).postDelayed({ + notificationManager.cancelAll() + }, 2000) } fun setCredentialContentIntent(user: User) { diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index f38273488f55..297d465c2bab 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -123,7 +123,6 @@ class FileDownloadWorker( notificationManager.init() addAccountUpdateListener() - setWorkerState(user) requestDownloads.forEach { downloadFile(it) } @@ -284,6 +283,7 @@ class FileDownloadWorker( return } + setWorkerState(user) Log_OC.e(TAG, "FilesDownloadWorker downloading: $downloadKey") val isAccountExist = accountManager.exists(currentDownload?.user?.toPlatformAccount()) From 11fa95d2b911b992ced5af85dc624685c8cc882a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 12:08:59 +0100 Subject: [PATCH 063/189] Fix code analytics Signed-off-by: alperozturk --- .../downloader/DownloadNotificationManager.kt | 2 ++ .../files/downloader/FileDownloadWorker.kt | 20 +++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 83917d883a37..720e58072525 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -44,6 +44,7 @@ import com.owncloud.android.utils.theme.ViewThemeUtils import java.io.File import java.security.SecureRandom +@Suppress("TooManyFunctions") class DownloadNotificationManager(private val context: Context, private val viewThemeUtils: ViewThemeUtils) { private var notification: Notification? = null @@ -198,6 +199,7 @@ class DownloadNotificationManager(private val context: Context, private val view notificationManager.cancel(R.string.downloader_download_in_progress_ticker) } + @Suppress("MagicNumber") fun dismissAll() { Handler(Looper.getMainLooper()).postDelayed({ notificationManager.cancelAll() diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 297d465c2bab..5f2843ece44e 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -161,6 +161,16 @@ class FileDownloadWorker( WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } + private fun cancelAllDownloads() { + pendingDownloads.all.forEach { + it.value.payload?.cancel() + } + } + + private fun removePendingDownload(accountName: String?) { + pendingDownloads.remove(accountName) + } + private fun notifyForFolderResult(folder: OCFile) { notificationManager.notifyForResult(null, null, folder, isAnyOperationFailed) } @@ -212,16 +222,6 @@ class FileDownloadWorker( } } - private fun removePendingDownload(accountName: String?) { - pendingDownloads.remove(accountName) - } - - private fun cancelAllDownloads() { - pendingDownloads.all.forEach { - it.value.payload?.cancel() - } - } - private fun setUser() { val accountName = inputData.keyValueMap[USER_NAME] as String user = accountManager.getUser(accountName).get() From 5a38769f8384b07b5f6f3c34dbb066b2c3c74666 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 12:19:12 +0100 Subject: [PATCH 064/189] Use same worker for file download Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadHelper.kt | 6 ++---- .../nextcloud/client/jobs/BackgroundJobManagerImpl.kt | 9 +++++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index e599755727ef..438419128556 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -60,10 +60,8 @@ class FileDownloadHelper { return false } - return backgroundJobManager.isStartFileDownloadJobScheduled( - user, - file - ) || FileDownloadWorker.isDownloading(user, file) + return FileDownloadWorker.isDownloading(user, file) || + (file.isFolder && backgroundJobManager.isStartFileDownloadJobScheduled(user, file)) } fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 8b4c2ef6ff48..26945772298f 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -86,6 +86,7 @@ internal class BackgroundJobManagerImpl( const val JOB_NOTIFICATION = "notification" const val JOB_ACCOUNT_REMOVAL = "account_removal" const val JOB_FILES_UPLOAD = "files_upload" + const val JOB_FOLDER_DOWNLOAD = "folder_download" const val JOB_FILES_DOWNLOAD = "files_download" const val JOB_PDF_GENERATION = "pdf_generation" const val JOB_IMMEDIATE_CALENDAR_BACKUP = "immediate_calendar_backup" @@ -509,7 +510,11 @@ internal class BackgroundJobManagerImpl( } private fun startFileDownloadJobTag(user: User, ocFile: OCFile): String { - return JOB_FILES_DOWNLOAD + user.accountName + ocFile.fileId + return if (ocFile.isFolder) { + JOB_FOLDER_DOWNLOAD + user.accountName + ocFile.fileId + } else { + JOB_FILES_DOWNLOAD + user.accountName + } } override fun isStartFileDownloadJobScheduled(user: User, ocFile: OCFile): Boolean { @@ -561,7 +566,7 @@ internal class BackgroundJobManagerImpl( .setInputData(data) .build() - workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) + workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.KEEP, request) } override fun getFileUploads(user: User): LiveData> { From 0f59254b2bb59d516be03bceddc8216b54852d7a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 14:23:27 +0100 Subject: [PATCH 065/189] Fix back to back download Signed-off-by: alperozturk --- .../java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 26945772298f..8149b24ed089 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -566,7 +566,7 @@ internal class BackgroundJobManagerImpl( .setInputData(data) .build() - workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.KEEP, request) + workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.APPEND, request) } override fun getFileUploads(user: User): LiveData> { From 8d7aec013ff4044ef01da4a71c67ad4bd6d0a318 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 14:55:12 +0100 Subject: [PATCH 066/189] Rename argument name Signed-off-by: alperozturk --- .../files/downloader/FileDownloadIntents.kt | 4 +- .../files/downloader/FileDownloadWorker.kt | 50 ++++++++++--------- .../client/jobs/BackgroundJobManagerImpl.kt | 10 ++-- .../android/services/SyncFolderHandler.java | 4 +- .../ui/activity/FileDisplayActivity.java | 2 +- .../ui/preview/PreviewImageActivity.java | 2 +- 6 files changed, 37 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt index 9725bbd69dda..2407018ca603 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt @@ -39,7 +39,7 @@ class FileDownloadIntents(private val context: Context) { linkedToRemotePath: String ): Intent { return Intent(FileDownloadWorker.getDownloadAddedMessage()).apply { - putExtra(FileDownloadWorker.ACCOUNT_NAME, download.user.accountName) + putExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME, download.user.accountName) putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) putExtra(FileDownloadWorker.EXTRA_LINKED_TO_PATH, linkedToRemotePath) setPackage(context.packageName) @@ -53,7 +53,7 @@ class FileDownloadIntents(private val context: Context) { ): Intent { return Intent(FileDownloadWorker.getDownloadFinishMessage()).apply { putExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) - putExtra(FileDownloadWorker.ACCOUNT_NAME, download.user.accountName) + putExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME, download.user.accountName) putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 5f2843ece44e..e1f6d6705e27 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -42,7 +42,6 @@ import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.files.services.IndexedForest import com.owncloud.android.lib.common.OwnCloudAccount -import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.OwnCloudClientManagerFactory import com.owncloud.android.lib.common.network.OnDatatransferProgressListener import com.owncloud.android.lib.common.operations.RemoteOperationResult @@ -71,21 +70,20 @@ class FileDownloadWorker( private var currentDownload: DownloadFileOperation? = null const val FILES_SEPARATOR = "," - const val FOLDER_PATH = "FOLDER_PATH" - const val USER_NAME = "USER" - const val FILE_PATH = "FILE_PATH" - const val FILES_PATH = "FILES_PATH" + const val FOLDER_REMOTE_PATH = "FOLDER_REMOTE_PATH" + const val FILE_REMOTE_PATH = "FILE_REMOTE_PATH" + const val FILES_REMOTE_PATH = "FILES_REMOTE_PATH" + const val ACCOUNT_NAME = "ACCOUNT_NAME" const val BEHAVIOUR = "BEHAVIOUR" const val DOWNLOAD_TYPE = "DOWNLOAD_TYPE" const val ACTIVITY_NAME = "ACTIVITY_NAME" const val PACKAGE_NAME = "PACKAGE_NAME" const val CONFLICT_UPLOAD_ID = "CONFLICT_UPLOAD_ID" - const val EXTRA_USER = "USER" - const val EXTRA_FILE = "FILE" - const val EXTRA_DOWNLOAD_RESULT = "RESULT" - const val EXTRA_REMOTE_PATH = "REMOTE_PATH" - const val EXTRA_LINKED_TO_PATH = "LINKED_TO" - const val ACCOUNT_NAME = "ACCOUNT_NAME" + + const val EXTRA_DOWNLOAD_RESULT = "EXTRA_DOWNLOAD_RESULT" + const val EXTRA_REMOTE_PATH = "EXTRA_REMOTE_PATH" + const val EXTRA_LINKED_TO_PATH = "EXTRA_LINKED_TO_PATH" + const val EXTRA_ACCOUNT_NAME = "EXTRA_ACCOUNT_NAME" fun isDownloading(user: User, file: OCFile): Boolean { return currentDownload?.file?.fileId == file.fileId && @@ -102,16 +100,20 @@ class FileDownloadWorker( } private val pendingDownloads = IndexedForest() + private var conflictUploadId: Long? = null private var lastPercent = 0 + private val intents = FileDownloadIntents(context) private val notificationManager = DownloadNotificationManager(context, viewThemeUtils) private var downloadProgressListener = FileDownloadProgressListener() + + private var user: User? = null private var currentUser = Optional.empty() - private var storageManager: FileDataStorageManager? = null + + private var currentUserFileStorageManager: FileDataStorageManager? = null private var fileDataStorageManager: FileDataStorageManager? = null - private var downloadClient: OwnCloudClient? = null - private var user: User? = null + private var folder: OCFile? = null private var isAnyOperationFailed = true @@ -223,22 +225,22 @@ class FileDownloadWorker( } private fun setUser() { - val accountName = inputData.keyValueMap[USER_NAME] as String + val accountName = inputData.keyValueMap[ACCOUNT_NAME] as String user = accountManager.getUser(accountName).get() fileDataStorageManager = FileDataStorageManager(user, context.contentResolver) } private fun setFolder() { - val folderPath = inputData.keyValueMap[FOLDER_PATH] as? String? + val folderPath = inputData.keyValueMap[FOLDER_REMOTE_PATH] as? String? if (folderPath != null) { - folder = storageManager?.getFileByEncryptedRemotePath(folderPath) + folder = currentUserFileStorageManager?.getFileByEncryptedRemotePath(folderPath) } } private fun getFiles(): List { val result = arrayListOf() - val filesPath = inputData.keyValueMap[FILES_PATH] as String? + val filesPath = inputData.keyValueMap[FILES_REMOTE_PATH] as String? val filesPathList = filesPath?.split(FILES_SEPARATOR) if (filesPathList != null) { @@ -248,7 +250,7 @@ class FileDownloadWorker( } } } else { - val remotePath = inputData.keyValueMap[FILE_PATH] as String + val remotePath = inputData.keyValueMap[FILE_REMOTE_PATH] as String fileDataStorageManager?.getFileByEncryptedRemotePath(remotePath)?.let { file -> result.add(file) } @@ -296,13 +298,13 @@ class FileDownloadWorker( var downloadResult: RemoteOperationResult<*>? = null try { val ocAccount = getOCAccountForDownload() - downloadClient = + val downloadClient = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, context) downloadResult = currentDownload?.execute(downloadClient) if (downloadResult?.isSuccess == true && currentDownload?.downloadType === DownloadType.DOWNLOAD) { getCurrentFile()?.let { - FileDownloadHelper.instance().saveFile(it, currentDownload, storageManager) + FileDownloadHelper.instance().saveFile(it, currentDownload, currentUserFileStorageManager) } } } catch (e: Exception) { @@ -328,16 +330,16 @@ class FileDownloadWorker( val currentDownloadUser = accountManager.getUser(currentDownloadAccount?.name) if (currentUser != currentDownloadUser) { currentUser = currentDownloadUser - storageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) + currentUserFileStorageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) } return currentDownloadUser.get().toOwnCloudAccount() } private fun getCurrentFile(): OCFile? { - var file: OCFile? = currentDownload?.file?.fileId?.let { storageManager?.getFileById(it) } + var file: OCFile? = currentDownload?.file?.fileId?.let { currentUserFileStorageManager?.getFileById(it) } if (file == null) { - file = storageManager?.getFileByDecryptedRemotePath(currentDownload?.file?.remotePath) + file = currentUserFileStorageManager?.getFileByDecryptedRemotePath(currentDownload?.file?.remotePath) } if (file == null) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 8149b24ed089..9597b0160c8b 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -523,9 +523,9 @@ internal class BackgroundJobManagerImpl( override fun startFolderDownloadJob(folder: OCFile, user: User, filesPath: List) { val data = workDataOf( - FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FOLDER_PATH to folder.remotePath, - FileDownloadWorker.FILES_PATH to filesPath.joinToString(FileDownloadWorker.FILES_SEPARATOR), + FileDownloadWorker.ACCOUNT_NAME to user.accountName, + FileDownloadWorker.FOLDER_REMOTE_PATH to folder.remotePath, + FileDownloadWorker.FILES_REMOTE_PATH to filesPath.joinToString(FileDownloadWorker.FILES_SEPARATOR), FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() ) @@ -552,8 +552,8 @@ internal class BackgroundJobManagerImpl( val tag = startFileDownloadJobTag(user, file) val data = workDataOf( - FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FILE_PATH to file.remotePath, + FileDownloadWorker.ACCOUNT_NAME to user.accountName, + FileDownloadWorker.FILE_REMOTE_PATH to file.remotePath, FileDownloadWorker.BEHAVIOUR to behaviour, FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), FileDownloadWorker.ACTIVITY_NAME to activityName, diff --git a/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java b/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java index c91702076d5b..7a5d4d25f2b2 100644 --- a/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java +++ b/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java @@ -170,7 +170,7 @@ public void cancel(Account account, OCFile file){ */ private void sendBroadcastNewSyncFolder(Account account, String remotePath) { Intent added = new Intent(FileDownloadWorker.Companion.getDownloadAddedMessage()); - added.putExtra(FileDownloadWorker.ACCOUNT_NAME, account.name); + added.putExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME, account.name); added.putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, remotePath); added.setPackage(mService.getPackageName()); LocalBroadcastManager.getInstance(mService.getApplicationContext()).sendBroadcast(added); @@ -183,7 +183,7 @@ private void sendBroadcastNewSyncFolder(Account account, String remotePath) { private void sendBroadcastFinishedSyncFolder(Account account, String remotePath, boolean success) { Intent finished = new Intent(FileDownloadWorker.Companion.getDownloadFinishMessage()); - finished.putExtra(FileDownloadWorker.ACCOUNT_NAME, account.name); + finished.putExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME, account.name); finished.putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, remotePath); finished.putExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, success); finished.setPackage(mService.getPackageName()); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 43d7a3a740a4..04cfc96f956c 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1472,7 +1472,7 @@ private boolean isAscendant(String linkedToRemotePath) { } private boolean isSameAccount(Intent intent) { - String accountName = intent.getStringExtra(FileDownloadWorker.ACCOUNT_NAME); + String accountName = intent.getStringExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME); return accountName != null && getAccount() != null && accountName.equals(getAccount().name); } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index ae8d07ec2046..261e1c0f8f22 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -507,7 +507,7 @@ public void onReceive(Context context, Intent intent) { } private void previewNewImage(Intent intent) { - String accountName = intent.getStringExtra(FileDownloadWorker.ACCOUNT_NAME); + String accountName = intent.getStringExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME); String downloadedRemotePath = intent.getStringExtra(FileDownloadWorker.EXTRA_REMOTE_PATH); String downloadBehaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); if (getAccount().name.equals(accountName) && downloadedRemotePath != null) { From 5a5b18bad0d32df157a39a276de74d8feb5d3f72 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 15:04:27 +0100 Subject: [PATCH 067/189] Fix cancel Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadHelper.kt | 6 ++++-- .../client/files/downloader/FileDownloadWorker.kt | 9 +++++++-- .../android/operations/DownloadFileOperation.java | 9 +++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 438419128556..75e266a4f230 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -66,12 +66,14 @@ class FileDownloadHelper { fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return + FileDownloadWorker.cancelCurrentDownload(user, file) backgroundJobManager.cancelFilesDownloadJob(user, file) } - fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation) { - if (currentDownload.user.nameEquals(accountName)) { + fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation?) { + if (currentDownload?.user?.nameEquals(accountName) == true) { currentDownload.file?.let { file -> + FileDownloadWorker.cancelCurrentDownload(currentDownload.user, file) backgroundJobManager.cancelFilesDownloadJob(currentDownload.user, file) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index e1f6d6705e27..508a9979e875 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -86,8 +86,13 @@ class FileDownloadWorker( const val EXTRA_ACCOUNT_NAME = "EXTRA_ACCOUNT_NAME" fun isDownloading(user: User, file: OCFile): Boolean { - return currentDownload?.file?.fileId == file.fileId && - currentDownload?.user?.accountName == user.accountName + return currentDownload?.isActive(user, file) ?: false + } + + fun cancelCurrentDownload(user: User, file: OCFile) { + if (currentDownload?.isActive(user, file) == true) { + currentDownload?.cancel() + } } fun getDownloadAddedMessage(): String { diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index 568467654fcf..d00ab8b6a12b 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -98,6 +98,15 @@ public DownloadFileOperation(User user, OCFile file, Context context) { this(user, file, null, null, null, context, DownloadType.DOWNLOAD); } + public boolean isActive(User user, OCFile file) { + if (user == null || file == null) { + return false; + } + + return getFile().getFileId() == file.getFileId() && + getUser().getAccountName().equals(user.getAccountName()); + } + public String getSavePath() { if (file.getStoragePath() != null) { File parentFile = new File(file.getStoragePath()).getParentFile(); From 1ada24583d3c03ed3c7dd923364c71dbc8798d68 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 15:08:22 +0100 Subject: [PATCH 068/189] Fix context memory leak Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadWorker.kt | 2 -- .../android/operations/DownloadFileOperation.java | 13 +++++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 508a9979e875..178761ef8475 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -24,7 +24,6 @@ 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 @@ -66,7 +65,6 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName - @SuppressLint("StaticFieldLeak") private var currentDownload: DownloadFileOperation? = null const val FILES_SEPARATOR = "," diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index d00ab8b6a12b..1aaca764934c 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -43,6 +43,7 @@ import java.io.File; import java.io.FileOutputStream; +import java.lang.ref.WeakReference; import java.util.HashSet; import java.util.Iterator; import java.util.Set; @@ -62,7 +63,7 @@ public class DownloadFileOperation extends RemoteOperation { private String packageName; private DownloadType downloadType; - private Context context; + private final WeakReference context; private Set dataTransferListeners = new HashSet<>(); private long modificationTimestamp; private DownloadFileRemoteOperation downloadOperation; @@ -90,7 +91,7 @@ public DownloadFileOperation(User user, this.behaviour = behaviour; this.activityName = activityName; this.packageName = packageName; - this.context = context; + this.context = new WeakReference<>(context); this.downloadType = downloadType; } @@ -203,13 +204,13 @@ protected RemoteOperationResult run(OwnCloudClient client) { // decrypt file if (file.isEncrypted()) { - FileDataStorageManager fileDataStorageManager = new FileDataStorageManager(user, context.getContentResolver()); + FileDataStorageManager fileDataStorageManager = new FileDataStorageManager(user, context.get().getContentResolver()); OCFile parent = fileDataStorageManager.getFileByPath(file.getParentRemotePath()); DecryptedFolderMetadata metadata = EncryptionUtils.downloadFolderMetadata(parent, client, - context, + context.get(), user); if (metadata == null) { @@ -227,7 +228,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { key, iv, authenticationTag, - new ArbitraryDataProviderImpl(context), + new ArbitraryDataProviderImpl(context.get()), user); try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile)) { @@ -247,7 +248,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { } else if (downloadType == DownloadType.EXPORT) { new FileExportUtils().exportFile(file.getFileName(), file.getMimeType(), - context.getContentResolver(), + context.get().getContentResolver(), null, tmpFile); if (!tmpFile.delete()) { From 508460d49dd776554ffd2de2acd6906524cdab43 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 15:35:49 +0100 Subject: [PATCH 069/189] Fix potential race condition Signed-off-by: alperozturk --- .../files/downloader/FileDownloadWorker.kt | 11 ++++++++--- .../operations/DownloadFileOperation.java | 18 +++++++++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 178761ef8475..3efb81a35d7b 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -66,6 +66,7 @@ class FileDownloadWorker( private val TAG = FileDownloadWorker::class.java.simpleName private var currentDownload: DownloadFileOperation? = null + private val lock = Any() const val FILES_SEPARATOR = "," const val FOLDER_REMOTE_PATH = "FOLDER_REMOTE_PATH" @@ -84,12 +85,16 @@ class FileDownloadWorker( const val EXTRA_ACCOUNT_NAME = "EXTRA_ACCOUNT_NAME" fun isDownloading(user: User, file: OCFile): Boolean { - return currentDownload?.isActive(user, file) ?: false + synchronized(lock) { + return currentDownload?.isActive(user, file) ?: false + } } fun cancelCurrentDownload(user: User, file: OCFile) { - if (currentDownload?.isActive(user, file) == true) { - currentDownload?.cancel() + synchronized(lock) { + if (currentDownload?.isActive(user, file) == true) { + currentDownload?.cancel() + } } } diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index 1aaca764934c..e0e28af5a40d 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -170,6 +170,11 @@ protected RemoteOperationResult run(OwnCloudClient client) { } } + Context operationContext = context.get(); + if (operationContext == null) { + return new RemoteOperationResult(RemoteOperationResult.ResultCode.UNKNOWN_ERROR); + } + RemoteOperationResult result; File newFile = null; boolean moved; @@ -190,6 +195,8 @@ protected RemoteOperationResult run(OwnCloudClient client) { result = downloadOperation.execute(client); + + if (result.isSuccess()) { modificationTimestamp = downloadOperation.getModificationTimestamp(); etag = downloadOperation.getEtag(); @@ -204,13 +211,13 @@ protected RemoteOperationResult run(OwnCloudClient client) { // decrypt file if (file.isEncrypted()) { - FileDataStorageManager fileDataStorageManager = new FileDataStorageManager(user, context.get().getContentResolver()); + FileDataStorageManager fileDataStorageManager = new FileDataStorageManager(user, operationContext.getContentResolver()); - OCFile parent = fileDataStorageManager.getFileByPath(file.getParentRemotePath()); + OCFile parent = fileDataStorageManager.getFileByEncryptedRemotePath(file.getParentRemotePath()); DecryptedFolderMetadata metadata = EncryptionUtils.downloadFolderMetadata(parent, client, - context.get(), + operationContext, user); if (metadata == null) { @@ -228,7 +235,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { key, iv, authenticationTag, - new ArbitraryDataProviderImpl(context.get()), + new ArbitraryDataProviderImpl(operationContext), user); try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile)) { @@ -248,7 +255,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { } else if (downloadType == DownloadType.EXPORT) { new FileExportUtils().exportFile(file.getFileName(), file.getMimeType(), - context.get().getContentResolver(), + operationContext.getContentResolver(), null, tmpFile); if (!tmpFile.delete()) { @@ -256,6 +263,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { } } } + Log_OC.i(TAG, "Download of " + file.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage()); From 11a8ec4ec1f34fef30874907b30f662cd41b049c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 12:03:22 +0100 Subject: [PATCH 070/189] Unify download notifications Signed-off-by: alperozturk --- .../downloader/DownloadNotificationManager.kt | 160 ++++-------------- .../files/downloader/FileDownloadIntents.kt | 15 ++ .../files/downloader/FileDownloadWorker.kt | 85 +++++----- .../client/jobs/BackgroundJobFactory.kt | 1 - app/src/main/res/values/strings.xml | 4 + 5 files changed, 97 insertions(+), 168 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 720e58072525..d0f381c418c5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -31,30 +31,27 @@ import android.os.Build import android.os.Handler import android.os.Looper import androidx.core.app.NotificationCompat -import com.nextcloud.client.account.User import com.owncloud.android.R -import com.owncloud.android.authentication.AuthenticatorActivity -import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.resources.files.FileUtils import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.ui.notifications.NotificationUtils -import com.owncloud.android.utils.ErrorMessageAdapter import com.owncloud.android.utils.theme.ViewThemeUtils import java.io.File -import java.security.SecureRandom @Suppress("TooManyFunctions") -class DownloadNotificationManager(private val context: Context, private val viewThemeUtils: ViewThemeUtils) { - - private var notification: Notification? = null - private lateinit var notificationBuilder: NotificationCompat.Builder +class DownloadNotificationManager( + private val id: Int, + private val context: Context, + private val viewThemeUtils: ViewThemeUtils +) { + + private var notification: Notification + private var notificationBuilder: NotificationCompat.Builder private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - fun init() { + init { notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply { setContentTitle(context.resources.getString(R.string.app_name)) - setContentText(context.resources.getString(R.string.worker_download)) setSmallIcon(R.drawable.notification_icon) setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) @@ -67,11 +64,9 @@ class DownloadNotificationManager(private val context: Context, private val view } @Suppress("MagicNumber") - fun notifyForStart(operation: DownloadFileOperation) { + fun prepareForStart(operation: DownloadFileOperation) { notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply { setSmallIcon(R.drawable.notification_icon) - setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) - setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) setOngoing(true) setProgress(100, 0, operation.size < 0) setContentText( @@ -84,141 +79,52 @@ class DownloadNotificationManager(private val context: Context, private val view if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) } + + notificationManager.notify( + id, + this.build() + ) } } - fun prepareForResult( - downloadResult: RemoteOperationResult<*>, - needsToUpdateCredentials: Boolean - ) { - val tickerId = getTickerId(downloadResult.isSuccess, needsToUpdateCredentials, null, null) - + fun prepareForResult() { notificationBuilder - .setTicker(context.getString(tickerId)) - .setContentTitle(context.getString(tickerId)) .setAutoCancel(true) .setOngoing(false) .setProgress(0, 0, false) } @Suppress("MagicNumber") - fun notifyForResult( - result: RemoteOperationResult<*>?, - download: DownloadFileOperation?, - folder: OCFile?, - isAnyOperationFailed: Boolean? - ) { - dismissDownloadInProgressNotification() - - val tickerId = getTickerId(result?.isSuccess, null, folder, isAnyOperationFailed) - val notifyId = SecureRandom().nextInt() - val resultText = getResultText(result, download, folder, isAnyOperationFailed) - + fun updateDownloadProgress(filePath: String, percent: Int, totalToTransfer: Long) { notificationBuilder.run { - setTicker(context.getString(tickerId)) - setContentText(resultText) - notificationManager.notify(notifyId, this.build()) - } - - NotificationUtils.cancelWithDelay( - notificationManager, - notifyId, - 2000 - ) - } - - private fun getResultText( - result: RemoteOperationResult<*>?, - download: DownloadFileOperation?, - folder: OCFile?, - isAnyOperationFailed: Boolean? - ): String { - return folder?.let { - getFolderResultText(isAnyOperationFailed, it) - } ?: if (result?.isSuccess == true) { - download?.file?.fileName ?: "" - } else { - ErrorMessageAdapter.getErrorCauseMessage(result, download, context.resources) - } - } - - private fun getFolderResultText(isAnyOperationFailed: Boolean?, folder: OCFile): String { - return if (isAnyOperationFailed == false) { - context.getString(R.string.downloader_folder_downloaded, folder.fileName) - } else { - context.getString(R.string.downloader_folder_download_failed, folder.fileName) - } - } - - private fun getTickerId( - isSuccess: Boolean?, - needsToUpdateCredentials: Boolean?, - folder: OCFile?, - isAnyOperationFailed: Boolean? - ): Int { - return if (needsToUpdateCredentials == true) { - R.string.downloader_download_failed_credentials_error - } else { - folder?.let { getFolderTickerId(isAnyOperationFailed) } ?: getFileTickerId(isSuccess) - } - } - - private fun getFileTickerId(isSuccess: Boolean?): Int { - return if (isSuccess == true) { - R.string.downloader_download_succeeded_ticker - } else { - R.string.downloader_download_failed_ticker - } - } - - private fun getFolderTickerId(isAnyOperationFailed: Boolean?): Int { - return if (isAnyOperationFailed == false) { - R.string.downloader_folder_downloaded - } else { - R.string.downloader_folder_download_failed + setProgress(100, percent, totalToTransfer < 0) + val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) + val text = + String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) + updateNotificationText(text) } } @Suppress("MagicNumber") - fun updateDownloadProgressNotification(filePath: String, percent: Int, totalToTransfer: Long) { - notificationBuilder.setProgress(100, percent, totalToTransfer < 0) - val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) - val text = - String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) - notificationBuilder.setContentText(text) - } - - fun showDownloadInProgressNotification() { - notificationManager.notify( - R.string.downloader_download_in_progress_ticker, - notificationBuilder.build() - ) - } - - fun dismissDownloadInProgressNotification() { - notificationManager.cancel(R.string.downloader_download_in_progress_ticker) + fun showCompleteNotification(text: String) { + Handler(Looper.getMainLooper()).postDelayed({ + updateNotificationText(text) + dismissNotification() + }, 3000) } @Suppress("MagicNumber") - fun dismissAll() { + fun dismissNotification() { Handler(Looper.getMainLooper()).postDelayed({ - notificationManager.cancelAll() + notificationManager.cancel(id) }, 2000) } - fun setCredentialContentIntent(user: User) { - val intent = Intent(context, AuthenticatorActivity::class.java).apply { - putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) - putExtra( - AuthenticatorActivity.EXTRA_ACTION, - AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN - ) - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) - addFlags(Intent.FLAG_FROM_BACKGROUND) + private fun updateNotificationText(text: String) { + notificationBuilder.run { + setContentText(text) + notificationManager.notify(id, this.build()) } - - setContentIntent(intent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE) } fun setContentIntent(intent: Intent, flag: Int) { diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt index 2407018ca603..78f15a07291d 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt @@ -23,6 +23,8 @@ package com.nextcloud.client.files.downloader import android.content.Context import android.content.Intent +import com.nextcloud.client.account.User +import com.owncloud.android.authentication.AuthenticatorActivity import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.ui.activity.FileActivity @@ -65,6 +67,19 @@ class FileDownloadIntents(private val context: Context) { } } + fun credentialContentIntent(user: User): Intent { + return Intent(context, AuthenticatorActivity::class.java).apply { + putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) + putExtra( + AuthenticatorActivity.EXTRA_ACTION, + AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN + ) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + addFlags(Intent.FLAG_FROM_BACKGROUND) + } + } + fun detailsIntent(operation: DownloadFileOperation?): Intent { return if (operation != null) { if (PreviewImageFragment.canBePreviewed(operation.file)) { diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 3efb81a35d7b..15a0f1f1bbe4 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -36,9 +36,9 @@ import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional import com.nextcloud.model.WorkerState import com.nextcloud.model.WorkerStateLiveData +import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.files.services.IndexedForest import com.owncloud.android.lib.common.OwnCloudAccount import com.owncloud.android.lib.common.OwnCloudClientManagerFactory @@ -49,14 +49,14 @@ import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType import com.owncloud.android.utils.theme.ViewThemeUtils +import java.security.SecureRandom import java.util.AbstractList import java.util.Vector @Suppress("LongParameterList", "TooManyFunctions") class FileDownloadWorker( - viewThemeUtils: ViewThemeUtils, + private val viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, - private val uploadsStorageManager: UploadsStorageManager, private var localBroadcastManager: LocalBroadcastManager, private val context: Context, params: WorkerParameters @@ -113,7 +113,7 @@ class FileDownloadWorker( private var lastPercent = 0 private val intents = FileDownloadIntents(context) - private val notificationManager = DownloadNotificationManager(context, viewThemeUtils) + private val notificationManager = DownloadNotificationManager(SecureRandom().nextInt(), context, viewThemeUtils) private var downloadProgressListener = FileDownloadProgressListener() private var user: User? = null @@ -123,28 +123,26 @@ class FileDownloadWorker( private var fileDataStorageManager: FileDataStorageManager? = null private var folder: OCFile? = null - private var isAnyOperationFailed = true + private var failedFileNames: ArrayList = arrayListOf() @Suppress("TooGenericExceptionCaught") override fun doWork(): Result { return try { val requestDownloads = getRequestDownloads() - notificationManager.init() addAccountUpdateListener() requestDownloads.forEach { downloadFile(it) } - folder?.let { - notifyForFolderResult(it) - } + showCompleteNotification() setIdleWorkerState() Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() } catch (t: Throwable) { + notificationManager.showCompleteNotification(context.getString(R.string.downloader_unexpected_error)) Log_OC.e(TAG, "Error caught at FilesDownloadWorker(): " + t.localizedMessage) Result.failure() } @@ -155,7 +153,7 @@ class FileDownloadWorker( removePendingDownload(currentDownload?.user?.accountName) cancelAllDownloads() - notificationManager.dismissAll() + notificationManager.dismissNotification() setIdleWorkerState() super.onStopped() @@ -166,6 +164,7 @@ class FileDownloadWorker( } private fun setIdleWorkerState() { + failedFileNames.clear() pendingDownloads.all.clear() currentDownload = null WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) @@ -181,8 +180,25 @@ class FileDownloadWorker( pendingDownloads.remove(accountName) } - private fun notifyForFolderResult(folder: OCFile) { - notificationManager.notifyForResult(null, null, folder, isAnyOperationFailed) + private fun showCompleteNotification() { + val result = if (failedFileNames.isEmpty()) { + getSuccessNotificationText() + } else { + val fileNames = failedFileNames.joinToString() + context.getString(R.string.downloader_files_download_failed, fileNames) + } + + notificationManager.showCompleteNotification(result) + } + + private fun getSuccessNotificationText(): String { + return if (folder != null) { + context.getString(R.string.downloader_folder_downloaded, folder?.fileName) + } else if (currentDownload?.file != null) { + context.getString(R.string.downloader_file_downloaded, currentDownload?.file?.fileName) + } else { + context.getString(R.string.downloader_download_completed) + } } private fun getRequestDownloads(): AbstractList { @@ -241,7 +257,7 @@ class FileDownloadWorker( private fun setFolder() { val folderPath = inputData.keyValueMap[FOLDER_REMOTE_PATH] as? String? if (folderPath != null) { - folder = currentUserFileStorageManager?.getFileByEncryptedRemotePath(folderPath) + folder = fileDataStorageManager?.getFileByEncryptedRemotePath(folderPath) } } @@ -327,9 +343,8 @@ class FileDownloadWorker( lastPercent = 0 notificationManager.run { - notifyForStart(download) + prepareForStart(download) setContentIntent(intents.detailsIntent(download), PendingIntent.FLAG_IMMUTABLE) - showDownloadInProgressNotification() } } @@ -360,7 +375,7 @@ class FileDownloadWorker( private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { result?.let { - isAnyOperationFailed = !it.isSuccess + checkOperationFailures(it) } val removeResult = pendingDownloads.removePayload( @@ -383,6 +398,14 @@ class FileDownloadWorker( } } + private fun checkOperationFailures(result: RemoteOperationResult<*>) { + if (!result.isSuccess) { + currentDownload?.file?.fileName?.let { fileName -> + failedFileNames.add(fileName) + } + } + } + private fun notifyDownloadResult( download: DownloadFileOperation, downloadResult: RemoteOperationResult<*> @@ -391,38 +414,21 @@ class FileDownloadWorker( return } - // TODO Check why we calling only for success? - if (downloadResult.isSuccess) { - dismissDownloadInProgressNotification() - } - val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) notificationManager.run { - prepareForResult(downloadResult, needsToUpdateCredentials) + prepareForResult() if (needsToUpdateCredentials) { - setCredentialContentIntent(download.user) + setContentIntent( + intents.credentialContentIntent(download.user), + PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE + ) } else { setContentIntent(intents.detailsIntent(null), PendingIntent.FLAG_IMMUTABLE) } - - if (folder == null) { - notifyForResult(downloadResult, download, null, null) - } } } - private fun dismissDownloadInProgressNotification() { - // TODO Check necessity of this function call - conflictUploadId?.let { - if (it > 0) { - uploadsStorageManager.removeUpload(it) - } - } - - notificationManager.dismissDownloadInProgressNotification() - } - override fun onAccountsUpdated(accounts: Array?) { if (!accountManager.exists(currentDownload?.user?.toPlatformAccount())) { currentDownload?.cancel() @@ -440,8 +446,7 @@ class FileDownloadWorker( if (percent != lastPercent) { notificationManager.run { - updateDownloadProgressNotification(filePath, percent, totalToTransfer) - showDownloadInProgressNotification() + updateDownloadProgress(filePath, percent, totalToTransfer) } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt index 865b787d5312..e3ab4308d8b7 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt @@ -259,7 +259,6 @@ class BackgroundJobFactory @Inject constructor( return FileDownloadWorker( viewThemeUtils.get(), accountManager, - uploadsStorageManager, localBroadcastManager.get(), context, params diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2ad28653e254..a93fa464772c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -168,14 +168,18 @@ Waiting to upload %1$s (%2$d) Downloading… + Downloads are completed %1$d%% Downloading %2$s Downloaded %1$s downloaded Download failed Could not download %1$s Not downloaded yet + Error occurred while downloading %s files Error occurred while downloading %s folder %s folder successfully downloaded + %s file successfully downloaded + Unexpected error occurred while downloading files Download failed, log in again Choose account Switch account From dbf8ca939410fa384e78d5a0a3cb4bfbbf2398fe Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 12:34:47 +0100 Subject: [PATCH 071/189] Add credentials error notification Signed-off-by: alperozturk --- .../client/files/downloader/DownloadNotificationManager.kt | 2 +- .../nextcloud/client/files/downloader/FileDownloadWorker.kt | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index d0f381c418c5..451aaf2235eb 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -120,7 +120,7 @@ class DownloadNotificationManager( }, 2000) } - private fun updateNotificationText(text: String) { + fun updateNotificationText(text: String) { notificationBuilder.run { setContentText(text) notificationManager.notify(id, this.build()) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 15a0f1f1bbe4..3b1469afc5d3 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -151,9 +151,9 @@ class FileDownloadWorker( override fun onStopped() { Log_OC.e(TAG, "FilesDownloadWorker stopped") - removePendingDownload(currentDownload?.user?.accountName) - cancelAllDownloads() notificationManager.dismissNotification() + cancelAllDownloads() + removePendingDownload(currentDownload?.user?.accountName) setIdleWorkerState() super.onStopped() @@ -419,6 +419,7 @@ class FileDownloadWorker( prepareForResult() if (needsToUpdateCredentials) { + updateNotificationText(context.getString(R.string.downloader_download_failed_credentials_error)) setContentIntent( intents.credentialContentIntent(download.user), PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE From b5a57fc55b4650318362fcb9a4cc060f2bc591a2 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 13:06:33 +0100 Subject: [PATCH 072/189] Fix sync icon for downloads in queue Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadHelper.kt | 2 +- .../client/files/downloader/FileDownloadWorker.kt | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 75e266a4f230..aa03b3b60971 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -60,7 +60,7 @@ class FileDownloadHelper { return false } - return FileDownloadWorker.isDownloading(user, file) || + return FileDownloadWorker.isFileInQueue(file) || (file.isFolder && backgroundJobManager.isStartFileDownloadJobScheduled(user, file)) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 3b1469afc5d3..6328315ecd6c 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -66,6 +66,7 @@ class FileDownloadWorker( private val TAG = FileDownloadWorker::class.java.simpleName private var currentDownload: DownloadFileOperation? = null + private var pendingDownloadFileIds: ArrayList = arrayListOf() private val lock = Any() const val FILES_SEPARATOR = "," @@ -84,10 +85,8 @@ class FileDownloadWorker( const val EXTRA_LINKED_TO_PATH = "EXTRA_LINKED_TO_PATH" const val EXTRA_ACCOUNT_NAME = "EXTRA_ACCOUNT_NAME" - fun isDownloading(user: User, file: OCFile): Boolean { - synchronized(lock) { - return currentDownload?.isActive(user, file) ?: false - } + fun isFileInQueue(file: OCFile): Boolean { + return pendingDownloadFileIds.contains(file.fileId) } fun cancelCurrentDownload(user: User, file: OCFile) { @@ -144,6 +143,7 @@ class FileDownloadWorker( } catch (t: Throwable) { notificationManager.showCompleteNotification(context.getString(R.string.downloader_unexpected_error)) Log_OC.e(TAG, "Error caught at FilesDownloadWorker(): " + t.localizedMessage) + setIdleWorkerState() Result.failure() } } @@ -166,6 +166,7 @@ class FileDownloadWorker( private fun setIdleWorkerState() { failedFileNames.clear() pendingDownloads.all.clear() + pendingDownloadFileIds.clear() currentDownload = null WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } @@ -234,6 +235,7 @@ class FileDownloadWorker( file.remotePath, operation ) + pendingDownloadFileIds.add(file.fileId) if (downloadKey != null) { requestedDownloads.add(downloadKey) @@ -382,6 +384,7 @@ class FileDownloadWorker( currentDownload?.user?.accountName, currentDownload?.remotePath ) + pendingDownloadFileIds.remove(currentDownload?.file?.fileId) val downloadResult = result ?: RemoteOperationResult(RuntimeException("Error downloading…")) From 0558c34718bd3830c9d24dcf81f000a5aeec3715 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 13:46:43 +0100 Subject: [PATCH 073/189] Add showNewNotification Signed-off-by: alperozturk --- .../downloader/DownloadNotificationManager.kt | 12 ++++++++- .../files/downloader/FileDownloadWorker.kt | 27 +++++++++---------- app/src/main/res/values/strings.xml | 3 +-- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 451aaf2235eb..11a12144167e 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -37,6 +37,7 @@ import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.ui.notifications.NotificationUtils import com.owncloud.android.utils.theme.ViewThemeUtils import java.io.File +import java.security.SecureRandom @Suppress("TooManyFunctions") class DownloadNotificationManager( @@ -120,7 +121,16 @@ class DownloadNotificationManager( }, 2000) } - fun updateNotificationText(text: String) { + fun showNewNotification(text: String) { + val notifyId = SecureRandom().nextInt() + + notificationBuilder.run { + setContentText(text) + notificationManager.notify(notifyId, this.build()) + } + } + + private fun updateNotificationText(text: String) { notificationBuilder.run { setContentText(text) notificationManager.notify(id, this.build()) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 6328315ecd6c..2f2404dfd6f5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -122,7 +122,6 @@ class FileDownloadWorker( private var fileDataStorageManager: FileDataStorageManager? = null private var folder: OCFile? = null - private var failedFileNames: ArrayList = arrayListOf() @Suppress("TooGenericExceptionCaught") override fun doWork(): Result { @@ -164,7 +163,6 @@ class FileDownloadWorker( } private fun setIdleWorkerState() { - failedFileNames.clear() pendingDownloads.all.clear() pendingDownloadFileIds.clear() currentDownload = null @@ -181,14 +179,9 @@ class FileDownloadWorker( pendingDownloads.remove(accountName) } + @Suppress("MagicNumber") private fun showCompleteNotification() { - val result = if (failedFileNames.isEmpty()) { - getSuccessNotificationText() - } else { - val fileNames = failedFileNames.joinToString() - context.getString(R.string.downloader_files_download_failed, fileNames) - } - + val result = getSuccessNotificationText() notificationManager.showCompleteNotification(result) } @@ -377,7 +370,7 @@ class FileDownloadWorker( private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { result?.let { - checkOperationFailures(it) + showFailedDownloadNotifications(it) } val removeResult = pendingDownloads.removePayload( @@ -401,11 +394,15 @@ class FileDownloadWorker( } } - private fun checkOperationFailures(result: RemoteOperationResult<*>) { + private fun showFailedDownloadNotifications(result: RemoteOperationResult<*>) { if (!result.isSuccess) { - currentDownload?.file?.fileName?.let { fileName -> - failedFileNames.add(fileName) - } + val fileName = currentDownload?.file?.fileName ?: "" + notificationManager.showNewNotification( + context.getString( + R.string.downloader_file_download_failed, + fileName + ) + ) } } @@ -422,7 +419,7 @@ class FileDownloadWorker( prepareForResult() if (needsToUpdateCredentials) { - updateNotificationText(context.getString(R.string.downloader_download_failed_credentials_error)) + showNewNotification(context.getString(R.string.downloader_download_failed_credentials_error)) setContentIntent( intents.credentialContentIntent(download.user), PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a93fa464772c..eef79cac313d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -175,8 +175,7 @@ Download failed Could not download %1$s Not downloaded yet - Error occurred while downloading %s files - Error occurred while downloading %s folder + Error occurred while downloading %s file %s folder successfully downloaded %s file successfully downloaded Unexpected error occurred while downloading files From 801e86f555ec5c41b08fbbf4c678f29f810d4233 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 13:52:24 +0100 Subject: [PATCH 074/189] Add user check for isFileInQueue Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadHelper.kt | 2 +- .../client/files/downloader/FileDownloadWorker.kt | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index aa03b3b60971..cb16c7eefc37 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -60,7 +60,7 @@ class FileDownloadHelper { return false } - return FileDownloadWorker.isFileInQueue(file) || + return FileDownloadWorker.isFileInQueue(user, file) || (file.isFolder && backgroundJobManager.isStartFileDownloadJobScheduled(user, file)) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 2f2404dfd6f5..3ffb6b65351c 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -66,7 +66,7 @@ class FileDownloadWorker( private val TAG = FileDownloadWorker::class.java.simpleName private var currentDownload: DownloadFileOperation? = null - private var pendingDownloadFileIds: ArrayList = arrayListOf() + private var pendingDownloadFileIds: ArrayList> = arrayListOf() private val lock = Any() const val FILES_SEPARATOR = "," @@ -85,8 +85,8 @@ class FileDownloadWorker( const val EXTRA_LINKED_TO_PATH = "EXTRA_LINKED_TO_PATH" const val EXTRA_ACCOUNT_NAME = "EXTRA_ACCOUNT_NAME" - fun isFileInQueue(file: OCFile): Boolean { - return pendingDownloadFileIds.contains(file.fileId) + fun isFileInQueue(user: User, file: OCFile): Boolean { + return pendingDownloadFileIds.contains(Pair(user.accountName, file.fileId)) } fun cancelCurrentDownload(user: User, file: OCFile) { @@ -228,7 +228,7 @@ class FileDownloadWorker( file.remotePath, operation ) - pendingDownloadFileIds.add(file.fileId) + pendingDownloadFileIds.add(Pair(user?.accountName, file.fileId)) if (downloadKey != null) { requestedDownloads.add(downloadKey) @@ -377,7 +377,7 @@ class FileDownloadWorker( currentDownload?.user?.accountName, currentDownload?.remotePath ) - pendingDownloadFileIds.remove(currentDownload?.file?.fileId) + pendingDownloadFileIds.remove(Pair(currentDownload?.user?.accountName, currentDownload?.file?.fileId)) val downloadResult = result ?: RemoteOperationResult(RuntimeException("Error downloading…")) From ec69cbc8fe137d4f9644d0ed6031004a42f5b144 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 14:36:40 +0100 Subject: [PATCH 075/189] Fix race condition for isFileInQueue Signed-off-by: alperozturk --- .../nextcloud/client/files/downloader/FileDownloadWorker.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 3ffb6b65351c..40ee07fe3d36 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -86,7 +86,9 @@ class FileDownloadWorker( const val EXTRA_ACCOUNT_NAME = "EXTRA_ACCOUNT_NAME" fun isFileInQueue(user: User, file: OCFile): Boolean { - return pendingDownloadFileIds.contains(Pair(user.accountName, file.fileId)) + synchronized(lock) { + return pendingDownloadFileIds.contains(Pair(user.accountName, file.fileId)) + } } fun cancelCurrentDownload(user: User, file: OCFile) { From 2fd1955bae759a8e224685923dd925d461040746 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 14:45:56 +0100 Subject: [PATCH 076/189] No need for clear for each worker Signed-off-by: alperozturk --- .../com/nextcloud/client/files/downloader/FileDownloadWorker.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 40ee07fe3d36..93a95cf34816 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -166,7 +166,6 @@ class FileDownloadWorker( private fun setIdleWorkerState() { pendingDownloads.all.clear() - pendingDownloadFileIds.clear() currentDownload = null WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } From 12f95c6b8e399857dccc2152f2ccdead48662460 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 14:55:15 +0100 Subject: [PATCH 077/189] Cancel action remove added Signed-off-by: alperozturk --- .../com/nextcloud/client/files/downloader/FileDownloadWorker.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 93a95cf34816..d01114303bcb 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -139,6 +139,7 @@ class FileDownloadWorker( showCompleteNotification() setIdleWorkerState() + Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() } catch (t: Throwable) { @@ -173,6 +174,7 @@ class FileDownloadWorker( private fun cancelAllDownloads() { pendingDownloads.all.forEach { it.value.payload?.cancel() + pendingDownloadFileIds.remove(Pair(it.value.payload?.user?.accountName, it.value.payload?.file?.fileId)) } } From e0b5fc1257925790e2a3e19c7dc3df45e4130989 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 15:01:10 +0100 Subject: [PATCH 078/189] Cancel All notification when sync canncelled Signed-off-by: alperozturk --- .../client/files/downloader/DownloadNotificationManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 11a12144167e..7a9ecfb6393e 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -117,7 +117,7 @@ class DownloadNotificationManager( @Suppress("MagicNumber") fun dismissNotification() { Handler(Looper.getMainLooper()).postDelayed({ - notificationManager.cancel(id) + notificationManager.cancelAll() }, 2000) } From bb2f2c7fc62bccd554690640aff17423abb80501 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 16:37:37 +0100 Subject: [PATCH 079/189] Fix cancel feature for individual file download inside folder Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 29 +++++-- .../files/downloader/FileDownloadWorker.kt | 78 +++++++++++++------ .../operations/DownloadFileOperation.java | 9 +-- app/src/main/res/values/strings.xml | 1 + 4 files changed, 81 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index cb16c7eefc37..6b8dcfe75f29 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -21,6 +21,8 @@ package com.nextcloud.client.files.downloader +import android.content.Intent +import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.nextcloud.client.account.User import com.nextcloud.client.jobs.BackgroundJobManager import com.owncloud.android.MainApp @@ -66,19 +68,32 @@ class FileDownloadHelper { fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return - FileDownloadWorker.cancelCurrentDownload(user, file) + + sendCancelEvent(user, file) backgroundJobManager.cancelFilesDownloadJob(user, file) } + private fun sendCancelEvent(user: User, file: OCFile) { + val intent = Intent(FileDownloadWorker.CANCEL_EVENT).apply { + putExtra(FileDownloadWorker.EVENT_ACCOUNT_NAME, user.accountName) + putExtra(FileDownloadWorker.EVENT_FILE_ID, file.fileId) + } + LocalBroadcastManager.getInstance(MainApp.getAppContext()).sendBroadcast(intent) + } + fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation?) { - if (currentDownload?.user?.nameEquals(accountName) == true) { - currentDownload.file?.let { file -> - FileDownloadWorker.cancelCurrentDownload(currentDownload.user, file) - backgroundJobManager.cancelFilesDownloadJob(currentDownload.user, file) - } + if (accountName == null || currentDownload == null) return + + val currentUser = currentDownload.user + val currentFile = currentDownload.file - currentDownload.cancel() + if (!currentUser.nameEquals(accountName)) { + return } + + currentDownload.cancel() + sendCancelEvent(currentUser, currentFile) + backgroundJobManager.cancelFilesDownloadJob(currentUser, currentFile) } fun saveFile( diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index d01114303bcb..c43225310fff 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -25,7 +25,10 @@ import android.accounts.Account import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener import android.app.PendingIntent +import android.content.BroadcastReceiver import android.content.Context +import android.content.Intent +import android.content.IntentFilter import androidx.core.util.component1 import androidx.core.util.component2 import androidx.localbroadcastmanager.content.LocalBroadcastManager @@ -55,7 +58,7 @@ import java.util.Vector @Suppress("LongParameterList", "TooManyFunctions") class FileDownloadWorker( - private val viewThemeUtils: ViewThemeUtils, + viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, private var localBroadcastManager: LocalBroadcastManager, private val context: Context, @@ -69,6 +72,10 @@ class FileDownloadWorker( private var pendingDownloadFileIds: ArrayList> = arrayListOf() private val lock = Any() + const val CANCEL_EVENT = "CANCEL_EVENT" + const val EVENT_ACCOUNT_NAME = "EVENT_ACCOUNT_NAME" + const val EVENT_FILE_ID = "EVENT_FILE_ID" + const val FILES_SEPARATOR = "," const val FOLDER_REMOTE_PATH = "FOLDER_REMOTE_PATH" const val FILE_REMOTE_PATH = "FILE_REMOTE_PATH" @@ -91,14 +98,6 @@ class FileDownloadWorker( } } - fun cancelCurrentDownload(user: User, file: OCFile) { - synchronized(lock) { - if (currentDownload?.isActive(user, file) == true) { - currentDownload?.cancel() - } - } - } - fun getDownloadAddedMessage(): String { return FileDownloadWorker::class.java.name + "DOWNLOAD_ADDED" } @@ -131,6 +130,7 @@ class FileDownloadWorker( val requestDownloads = getRequestDownloads() addAccountUpdateListener() + registerCancelEvent() requestDownloads.forEach { downloadFile(it) @@ -166,11 +166,37 @@ class FileDownloadWorker( } private fun setIdleWorkerState() { - pendingDownloads.all.clear() currentDownload = null + LocalBroadcastManager.getInstance(context).unregisterReceiver(cancelEventReceiver) WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } + private fun getEventPair(intent: Intent): Pair? { + val fileId = intent.getLongExtra(EVENT_FILE_ID, -1L) + val accountName = intent.getStringExtra(EVENT_ACCOUNT_NAME) + + return if (fileId != -1L && accountName != null) { + Pair(accountName, fileId) + } else { + null + } + } + + private fun registerCancelEvent() { + val filter = IntentFilter(CANCEL_EVENT) + LocalBroadcastManager.getInstance(context).registerReceiver(cancelEventReceiver, filter) + } + + private val cancelEventReceiver: BroadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val (accountName, fileId) = getEventPair(intent) ?: return + + pendingDownloads.all.forEach { + it.value.payload?.cancel(accountName, fileId) + } + } + } + private fun cancelAllDownloads() { pendingDownloads.all.forEach { it.value.payload?.cancel() @@ -184,18 +210,15 @@ class FileDownloadWorker( @Suppress("MagicNumber") private fun showCompleteNotification() { - val result = getSuccessNotificationText() - notificationManager.showCompleteNotification(result) - } - - private fun getSuccessNotificationText(): String { - return if (folder != null) { + val successText = if (folder != null) { context.getString(R.string.downloader_folder_downloaded, folder?.fileName) } else if (currentDownload?.file != null) { context.getString(R.string.downloader_file_downloaded, currentDownload?.file?.fileName) } else { context.getString(R.string.downloader_download_completed) } + + notificationManager.showCompleteNotification(successText) } private fun getRequestDownloads(): AbstractList { @@ -398,15 +421,24 @@ class FileDownloadWorker( } private fun showFailedDownloadNotifications(result: RemoteOperationResult<*>) { - if (!result.isSuccess) { - val fileName = currentDownload?.file?.fileName ?: "" - notificationManager.showNewNotification( - context.getString( - R.string.downloader_file_download_failed, - fileName - ) + if (result.isSuccess) { + return + } + + val fileName = currentDownload?.file?.fileName ?: "" + val failMessage = if (result.isCancelled) { + context.getString( + R.string.downloader_file_download_cancelled, + fileName + ) + } else { + context.getString( + R.string.downloader_file_download_failed, + fileName ) } + + notificationManager.showNewNotification(failMessage) } private fun notifyDownloadResult( diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index e0e28af5a40d..9bfbbd167112 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -99,13 +99,10 @@ public DownloadFileOperation(User user, OCFile file, Context context) { this(user, file, null, null, null, context, DownloadType.DOWNLOAD); } - public boolean isActive(User user, OCFile file) { - if (user == null || file == null) { - return false; + public void cancel(String accountName, long fileId) { + if (getFile().getFileId() == fileId && getUser().getAccountName().equals(accountName)) { + cancel(); } - - return getFile().getFileId() == file.getFileId() && - getUser().getAccountName().equals(user.getAccountName()); } public String getSavePath() { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eef79cac313d..ddb012e5e173 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -175,6 +175,7 @@ Download failed Could not download %1$s Not downloaded yet + %s file download cancelled Error occurred while downloading %s file %s folder successfully downloaded %s file successfully downloaded From 4a5d75a325917efc631bb67c9b9f8f8e6275ab05 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Jan 2024 10:19:17 +0100 Subject: [PATCH 080/189] Use unique tag for all download type to fix sync problems Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 24 +++++++++---------- .../files/downloader/FileDownloadWorker.kt | 17 +++---------- .../client/jobs/BackgroundJobManager.kt | 4 ++-- .../client/jobs/BackgroundJobManagerImpl.kt | 22 +++++++---------- .../operations/DownloadFileOperation.java | 2 +- .../ui/activity/FileDisplayActivity.java | 4 ++-- 6 files changed, 29 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 6b8dcfe75f29..344c1622e804 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -62,23 +62,15 @@ class FileDownloadHelper { return false } - return FileDownloadWorker.isFileInQueue(user, file) || - (file.isFolder && backgroundJobManager.isStartFileDownloadJobScheduled(user, file)) + return backgroundJobManager.isStartFileDownloadJobScheduled(user, file.fileId) || + backgroundJobManager.isStartFileDownloadJobScheduled(user, file.parentId) } fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return sendCancelEvent(user, file) - backgroundJobManager.cancelFilesDownloadJob(user, file) - } - - private fun sendCancelEvent(user: User, file: OCFile) { - val intent = Intent(FileDownloadWorker.CANCEL_EVENT).apply { - putExtra(FileDownloadWorker.EVENT_ACCOUNT_NAME, user.accountName) - putExtra(FileDownloadWorker.EVENT_FILE_ID, file.fileId) - } - LocalBroadcastManager.getInstance(MainApp.getAppContext()).sendBroadcast(intent) + backgroundJobManager.cancelFilesDownloadJob(user, file.fileId) } fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation?) { @@ -93,7 +85,15 @@ class FileDownloadHelper { currentDownload.cancel() sendCancelEvent(currentUser, currentFile) - backgroundJobManager.cancelFilesDownloadJob(currentUser, currentFile) + backgroundJobManager.cancelFilesDownloadJob(currentUser, currentFile.fileId) + } + + private fun sendCancelEvent(user: User, file: OCFile) { + val intent = Intent(FileDownloadWorker.CANCEL_EVENT).apply { + putExtra(FileDownloadWorker.EVENT_ACCOUNT_NAME, user.accountName) + putExtra(FileDownloadWorker.EVENT_FILE_ID, file.fileId) + } + LocalBroadcastManager.getInstance(MainApp.getAppContext()).sendBroadcast(intent) } fun saveFile( diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index c43225310fff..cb0a4f70d4f3 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -68,10 +68,6 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName - private var currentDownload: DownloadFileOperation? = null - private var pendingDownloadFileIds: ArrayList> = arrayListOf() - private val lock = Any() - const val CANCEL_EVENT = "CANCEL_EVENT" const val EVENT_ACCOUNT_NAME = "EVENT_ACCOUNT_NAME" const val EVENT_FILE_ID = "EVENT_FILE_ID" @@ -92,12 +88,6 @@ class FileDownloadWorker( const val EXTRA_LINKED_TO_PATH = "EXTRA_LINKED_TO_PATH" const val EXTRA_ACCOUNT_NAME = "EXTRA_ACCOUNT_NAME" - fun isFileInQueue(user: User, file: OCFile): Boolean { - synchronized(lock) { - return pendingDownloadFileIds.contains(Pair(user.accountName, file.fileId)) - } - } - fun getDownloadAddedMessage(): String { return FileDownloadWorker::class.java.name + "DOWNLOAD_ADDED" } @@ -107,6 +97,7 @@ class FileDownloadWorker( } } + private var currentDownload: DownloadFileOperation? = null private val pendingDownloads = IndexedForest() private var conflictUploadId: Long? = null @@ -192,7 +183,7 @@ class FileDownloadWorker( val (accountName, fileId) = getEventPair(intent) ?: return pendingDownloads.all.forEach { - it.value.payload?.cancel(accountName, fileId) + it.value.payload?.cancelMatchingOperation(accountName, fileId) } } } @@ -200,7 +191,6 @@ class FileDownloadWorker( private fun cancelAllDownloads() { pendingDownloads.all.forEach { it.value.payload?.cancel() - pendingDownloadFileIds.remove(Pair(it.value.payload?.user?.accountName, it.value.payload?.file?.fileId)) } } @@ -254,7 +244,6 @@ class FileDownloadWorker( file.remotePath, operation ) - pendingDownloadFileIds.add(Pair(user?.accountName, file.fileId)) if (downloadKey != null) { requestedDownloads.add(downloadKey) @@ -290,6 +279,7 @@ class FileDownloadWorker( if (filesPathList != null) { filesPathList.forEach { + // FIXME Check if folder content not exist, DownloadFileOperation will not download via content fileDataStorageManager?.getFileByEncryptedRemotePath(it)?.let { file -> result.add(file) } @@ -403,7 +393,6 @@ class FileDownloadWorker( currentDownload?.user?.accountName, currentDownload?.remotePath ) - pendingDownloadFileIds.remove(Pair(currentDownload?.user?.accountName, currentDownload?.file?.fileId)) val downloadResult = result ?: RemoteOperationResult(RuntimeException("Error downloading…")) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 0a37bc0585da..9fc2879be6b3 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -145,9 +145,9 @@ interface BackgroundJobManager { fun getFileUploads(user: User): LiveData> fun cancelFilesUploadJob(user: User) - fun cancelFilesDownloadJob(user: User, ocFile: OCFile) + fun cancelFilesDownloadJob(user: User, fileId: Long) - fun isStartFileDownloadJobScheduled(user: User, ocFile: OCFile): Boolean + fun isStartFileDownloadJobScheduled(user: User, fileId: Long): Boolean @Suppress("LongParameterList") fun startFileDownloadJob( diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 9597b0160c8b..948dc62eac06 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -509,16 +509,12 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_FILES_UPLOAD + user.accountName, ExistingWorkPolicy.KEEP, request) } - private fun startFileDownloadJobTag(user: User, ocFile: OCFile): String { - return if (ocFile.isFolder) { - JOB_FOLDER_DOWNLOAD + user.accountName + ocFile.fileId - } else { - JOB_FILES_DOWNLOAD + user.accountName - } + private fun startFileDownloadJobTag(user: User, fileId: Long): String { + return JOB_FOLDER_DOWNLOAD + user.accountName + fileId } - override fun isStartFileDownloadJobScheduled(user: User, ocFile: OCFile): Boolean { - return workManager.isWorkScheduled(startFileDownloadJobTag(user, ocFile)) + override fun isStartFileDownloadJobScheduled(user: User, fileId: Long): Boolean { + return workManager.isWorkScheduled(startFileDownloadJobTag(user, fileId)) } override fun startFolderDownloadJob(folder: OCFile, user: User, filesPath: List) { @@ -529,7 +525,7 @@ internal class BackgroundJobManagerImpl( FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() ) - val tag = startFileDownloadJobTag(user, folder) + val tag = startFileDownloadJobTag(user, folder.fileId) val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .addTag(tag) @@ -549,7 +545,7 @@ internal class BackgroundJobManagerImpl( packageName: String, conflictUploadId: Long? ) { - val tag = startFileDownloadJobTag(user, file) + val tag = startFileDownloadJobTag(user, file.fileId) val data = workDataOf( FileDownloadWorker.ACCOUNT_NAME to user.accountName, @@ -566,7 +562,7 @@ internal class BackgroundJobManagerImpl( .setInputData(data) .build() - workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.APPEND, request) + workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) } override fun getFileUploads(user: User): LiveData> { @@ -578,8 +574,8 @@ internal class BackgroundJobManagerImpl( workManager.cancelJob(JOB_FILES_UPLOAD, user) } - override fun cancelFilesDownloadJob(user: User, ocFile: OCFile) { - workManager.cancelAllWorkByTag(startFileDownloadJobTag(user, ocFile)) + override fun cancelFilesDownloadJob(user: User, fileId: Long) { + workManager.cancelAllWorkByTag(startFileDownloadJobTag(user, fileId)) } override fun startPdfGenerateAndUploadWork( diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index 9bfbbd167112..65e89fece9cd 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -99,7 +99,7 @@ public DownloadFileOperation(User user, OCFile file, Context context) { this(user, file, null, null, null, context, DownloadType.DOWNLOAD); } - public void cancel(String accountName, long fileId) { + public void cancelMatchingOperation(String accountName, long fileId) { if (getFile().getFileId() == fileId && getUser().getAccountName().equals(accountName)) { cancel(); } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 04cfc96f956c..ceb0ce1110f1 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -287,7 +287,7 @@ protected void onCreate(Bundle savedInstanceState) { checkStoragePath(); initSyncBroadcastReceiver(); - observeDownloadWorkerState(); + observeWorkerState(); } @SuppressWarnings("unchecked") @@ -1562,7 +1562,7 @@ public boolean isDrawerIndicatorAvailable() { return isRoot(getCurrentDir()); } - private void observeDownloadWorkerState() { + private void observeWorkerState() { WorkerStateLiveData.Companion.instance().observe(this, state -> { if (state instanceof WorkerState.Download) { Log_OC.d(TAG, "Download worker started"); From 9b8829701b1eac085e311a57bbd45dad984ee11b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Jan 2024 10:29:31 +0100 Subject: [PATCH 081/189] Fix cancel for unique tag Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 1 + .../files/downloader/FileDownloadWorker.kt | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 344c1622e804..e7897ee5e032 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -69,6 +69,7 @@ class FileDownloadHelper { fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return + FileDownloadWorker.pauseWork() sendCancelEvent(user, file) backgroundJobManager.cancelFilesDownloadJob(user, file.fileId) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index cb0a4f70d4f3..bcff10469190 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -55,6 +55,7 @@ import com.owncloud.android.utils.theme.ViewThemeUtils import java.security.SecureRandom import java.util.AbstractList import java.util.Vector +import java.util.concurrent.atomic.AtomicBoolean @Suppress("LongParameterList", "TooManyFunctions") class FileDownloadWorker( @@ -68,6 +69,16 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName + private val shouldContinueExecution = AtomicBoolean(true) + + fun pauseWork() { + shouldContinueExecution.set(false) + } + + fun resumeWork() { + shouldContinueExecution.set(true) + } + const val CANCEL_EVENT = "CANCEL_EVENT" const val EVENT_ACCOUNT_NAME = "EVENT_ACCOUNT_NAME" const val EVENT_FILE_ID = "EVENT_FILE_ID" @@ -124,6 +135,10 @@ class FileDownloadWorker( registerCancelEvent() requestDownloads.forEach { + if (!shouldContinueExecution.get()) { + return@forEach + } + downloadFile(it) } @@ -185,6 +200,8 @@ class FileDownloadWorker( pendingDownloads.all.forEach { it.value.payload?.cancelMatchingOperation(accountName, fileId) } + + resumeWork() } } @@ -212,6 +229,7 @@ class FileDownloadWorker( } private fun getRequestDownloads(): AbstractList { + shouldContinueExecution.set(true) setUser() setFolder() val files = getFiles() @@ -279,7 +297,6 @@ class FileDownloadWorker( if (filesPathList != null) { filesPathList.forEach { - // FIXME Check if folder content not exist, DownloadFileOperation will not download via content fileDataStorageManager?.getFileByEncryptedRemotePath(it)?.let { file -> result.add(file) } From 3099ff3991855e65131d7b5383ed0e1eb4f3f332 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Jan 2024 10:46:08 +0100 Subject: [PATCH 082/189] Rename worker observer func Signed-off-by: alperozturk --- .../com/owncloud/android/ui/preview/PreviewImageActivity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 261e1c0f8f22..52b08446117c 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -152,7 +152,7 @@ protected void onCreate(Bundle savedInstanceState) { mRequestWaitingForBinder = false; } - observeDownloadWorkerState(); + observeWorkerState(); } public void toggleActionBarVisibility(boolean hide) { @@ -306,7 +306,7 @@ private void onSynchronizeFileOperationFinish(RemoteOperationResult result) { } } - private void observeDownloadWorkerState() { + private void observeWorkerState() { WorkerStateLiveData.Companion.instance().observe(this, state -> { if (state instanceof WorkerState.Download) { Log_OC.d(TAG, "Download worker started"); From 25ff9e884a97897f6c9bed20e5e5261e9825c846 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Jan 2024 10:57:12 +0100 Subject: [PATCH 083/189] Prevent unnecessary file download Signed-off-by: alperozturk --- .../java/com/owncloud/android/ui/activity/FileActivity.java | 5 ----- .../owncloud/android/ui/preview/PreviewImageActivity.java | 5 +---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index fca1cbd96bc1..151d177df8cb 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -228,15 +228,10 @@ protected void onCreate(Bundle savedInstanceState) { } } - mOperationsServiceConnection = new OperationsServiceConnection(); bindService(new Intent(this, OperationsService.class), mOperationsServiceConnection, Context.BIND_AUTO_CREATE); - if (user != null) { - FileDownloadHelper.Companion.instance().downloadFile(user, mFile); - } - mUploadServiceConnection = newTransferenceServiceConnection(); if (mUploadServiceConnection != null) { bindService(new Intent(this, FileUploader.class), mUploadServiceConnection, diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 52b08446117c..0fbf73a091a3 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -420,10 +420,7 @@ public void requestForDownload(OCFile file) { public void requestForDownload(OCFile file, String downloadBehaviour) { final User user = getUser().orElseThrow(RuntimeException::new); - - if (!FileDownloadHelper.Companion.instance().isDownloading(user, file)) { - FileDownloadHelper.Companion.instance().downloadFile(user, file, downloadBehaviour, DownloadType.DOWNLOAD, "", "", null); - } + FileDownloadHelper.Companion.instance().downloadFileIfNotStartedBefore(user, file); } /** From 2754cc6ac62291211a9bbb1d172f56b4089615cf Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Jan 2024 11:16:10 +0100 Subject: [PATCH 084/189] Fix cancel Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 15 +---- .../files/downloader/FileDownloadWorker.kt | 56 ++----------------- 2 files changed, 7 insertions(+), 64 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index e7897ee5e032..9984549be9da 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -21,8 +21,6 @@ package com.nextcloud.client.files.downloader -import android.content.Intent -import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.nextcloud.client.account.User import com.nextcloud.client.jobs.BackgroundJobManager import com.owncloud.android.MainApp @@ -69,8 +67,7 @@ class FileDownloadHelper { fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return - FileDownloadWorker.pauseWork() - sendCancelEvent(user, file) + FileDownloadWorker.cancelOperation(user.accountName, file.fileId) backgroundJobManager.cancelFilesDownloadJob(user, file.fileId) } @@ -85,18 +82,10 @@ class FileDownloadHelper { } currentDownload.cancel() - sendCancelEvent(currentUser, currentFile) + FileDownloadWorker.cancelOperation(currentUser.accountName, currentFile.fileId) backgroundJobManager.cancelFilesDownloadJob(currentUser, currentFile.fileId) } - private fun sendCancelEvent(user: User, file: OCFile) { - val intent = Intent(FileDownloadWorker.CANCEL_EVENT).apply { - putExtra(FileDownloadWorker.EVENT_ACCOUNT_NAME, user.accountName) - putExtra(FileDownloadWorker.EVENT_FILE_ID, file.fileId) - } - LocalBroadcastManager.getInstance(MainApp.getAppContext()).sendBroadcast(intent) - } - fun saveFile( file: OCFile, currentDownload: DownloadFileOperation?, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index bcff10469190..b11c6300604d 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -25,10 +25,7 @@ import android.accounts.Account import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener import android.app.PendingIntent -import android.content.BroadcastReceiver import android.content.Context -import android.content.Intent -import android.content.IntentFilter import androidx.core.util.component1 import androidx.core.util.component2 import androidx.localbroadcastmanager.content.LocalBroadcastManager @@ -55,7 +52,6 @@ import com.owncloud.android.utils.theme.ViewThemeUtils import java.security.SecureRandom import java.util.AbstractList import java.util.Vector -import java.util.concurrent.atomic.AtomicBoolean @Suppress("LongParameterList", "TooManyFunctions") class FileDownloadWorker( @@ -69,20 +65,14 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName - private val shouldContinueExecution = AtomicBoolean(true) + private val pendingDownloads = IndexedForest() - fun pauseWork() { - shouldContinueExecution.set(false) - } - - fun resumeWork() { - shouldContinueExecution.set(true) + fun cancelOperation(accountName: String, fileId: Long) { + pendingDownloads.all.forEach { + it.value.payload?.cancelMatchingOperation(accountName, fileId) + } } - const val CANCEL_EVENT = "CANCEL_EVENT" - const val EVENT_ACCOUNT_NAME = "EVENT_ACCOUNT_NAME" - const val EVENT_FILE_ID = "EVENT_FILE_ID" - const val FILES_SEPARATOR = "," const val FOLDER_REMOTE_PATH = "FOLDER_REMOTE_PATH" const val FILE_REMOTE_PATH = "FILE_REMOTE_PATH" @@ -109,7 +99,6 @@ class FileDownloadWorker( } private var currentDownload: DownloadFileOperation? = null - private val pendingDownloads = IndexedForest() private var conflictUploadId: Long? = null private var lastPercent = 0 @@ -132,13 +121,8 @@ class FileDownloadWorker( val requestDownloads = getRequestDownloads() addAccountUpdateListener() - registerCancelEvent() requestDownloads.forEach { - if (!shouldContinueExecution.get()) { - return@forEach - } - downloadFile(it) } @@ -173,38 +157,9 @@ class FileDownloadWorker( private fun setIdleWorkerState() { currentDownload = null - LocalBroadcastManager.getInstance(context).unregisterReceiver(cancelEventReceiver) WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } - private fun getEventPair(intent: Intent): Pair? { - val fileId = intent.getLongExtra(EVENT_FILE_ID, -1L) - val accountName = intent.getStringExtra(EVENT_ACCOUNT_NAME) - - return if (fileId != -1L && accountName != null) { - Pair(accountName, fileId) - } else { - null - } - } - - private fun registerCancelEvent() { - val filter = IntentFilter(CANCEL_EVENT) - LocalBroadcastManager.getInstance(context).registerReceiver(cancelEventReceiver, filter) - } - - private val cancelEventReceiver: BroadcastReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - val (accountName, fileId) = getEventPair(intent) ?: return - - pendingDownloads.all.forEach { - it.value.payload?.cancelMatchingOperation(accountName, fileId) - } - - resumeWork() - } - } - private fun cancelAllDownloads() { pendingDownloads.all.forEach { it.value.payload?.cancel() @@ -229,7 +184,6 @@ class FileDownloadWorker( } private fun getRequestDownloads(): AbstractList { - shouldContinueExecution.set(true) setUser() setFolder() val files = getFiles() From 457f01dfd478a53bc194fa7328949e18d80e5433 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Jan 2024 11:24:49 +0100 Subject: [PATCH 085/189] Fix cancel notification Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadWorker.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index b11c6300604d..427cdfaa744e 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -291,6 +291,8 @@ class FileDownloadWorker( return } + val fileName = currentDownload?.file?.fileName + setWorkerState(user) Log_OC.e(TAG, "FilesDownloadWorker downloading: $downloadKey") @@ -317,7 +319,7 @@ class FileDownloadWorker( Log_OC.e(TAG, "Error downloading", e) downloadResult = RemoteOperationResult(e) } finally { - cleanupDownloadProcess(downloadResult) + cleanupDownloadProcess(downloadResult, fileName) } } @@ -355,9 +357,9 @@ class FileDownloadWorker( return file } - private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { + private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?, fileName: String?) { result?.let { - showFailedDownloadNotifications(it) + showFailedDownloadNotifications(it, fileName) } val removeResult = pendingDownloads.removePayload( @@ -380,12 +382,11 @@ class FileDownloadWorker( } } - private fun showFailedDownloadNotifications(result: RemoteOperationResult<*>) { + private fun showFailedDownloadNotifications(result: RemoteOperationResult<*>, fileName: String?) { if (result.isSuccess) { return } - val fileName = currentDownload?.file?.fileName ?: "" val failMessage = if (result.isCancelled) { context.getString( R.string.downloader_file_download_cancelled, From e9e74ba8fbdb4a20051c5f4607fbf30cec8067a6 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Jan 2024 15:56:30 +0100 Subject: [PATCH 086/189] Fix Cancel Notification Appearance and Progress Bar Visibility Signed-off-by: alperozturk --- .../downloader/DownloadNotificationManager.kt | 13 +++++++++---- .../client/files/downloader/FileDownloadWorker.kt | 14 +++++++++++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 7a9ecfb6393e..88c50e5fb3e9 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -102,14 +102,14 @@ class DownloadNotificationManager( val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) val text = String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) - updateNotificationText(text) + updateNotificationText(text, false) } } @Suppress("MagicNumber") fun showCompleteNotification(text: String) { Handler(Looper.getMainLooper()).postDelayed({ - updateNotificationText(text) + updateNotificationText(text, true) dismissNotification() }, 3000) } @@ -117,7 +117,7 @@ class DownloadNotificationManager( @Suppress("MagicNumber") fun dismissNotification() { Handler(Looper.getMainLooper()).postDelayed({ - notificationManager.cancelAll() + notificationManager.cancel(id) }, 2000) } @@ -125,13 +125,18 @@ class DownloadNotificationManager( val notifyId = SecureRandom().nextInt() notificationBuilder.run { + setProgress(0, 0, false) setContentText(text) notificationManager.notify(notifyId, this.build()) } } - private fun updateNotificationText(text: String) { + private fun updateNotificationText(text: String, cancelProgressBar: Boolean) { notificationBuilder.run { + if (cancelProgressBar) { + setProgress(0, 0, false) + } + setContentText(text) notificationManager.notify(id, this.build()) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 427cdfaa744e..bf3c165f3df8 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -114,6 +114,7 @@ class FileDownloadWorker( private var fileDataStorageManager: FileDataStorageManager? = null private var folder: OCFile? = null + private var isAnyOperationFailed = false @Suppress("TooGenericExceptionCaught") override fun doWork(): Result { @@ -126,8 +127,7 @@ class FileDownloadWorker( downloadFile(it) } - showCompleteNotification() - + showSuccessNotification() setIdleWorkerState() Log_OC.e(TAG, "FilesDownloadWorker successfully completed") @@ -171,7 +171,12 @@ class FileDownloadWorker( } @Suppress("MagicNumber") - private fun showCompleteNotification() { + private fun showSuccessNotification() { + if (isAnyOperationFailed) { + notificationManager.dismissNotification() + return + } + val successText = if (folder != null) { context.getString(R.string.downloader_folder_downloaded, folder?.fileName) } else if (currentDownload?.file != null) { @@ -184,6 +189,7 @@ class FileDownloadWorker( } private fun getRequestDownloads(): AbstractList { + isAnyOperationFailed = false setUser() setFolder() val files = getFiles() @@ -387,6 +393,8 @@ class FileDownloadWorker( return } + isAnyOperationFailed = true + val failMessage = if (result.isCancelled) { context.getString( R.string.downloader_file_download_cancelled, From be1fed8f845149a6ca949bdbe1a1374ec8033800 Mon Sep 17 00:00:00 2001 From: Jonas Mayer Date: Tue, 9 Jan 2024 18:02:19 +0100 Subject: [PATCH 087/189] Improve Notifications Signed-off-by: Jonas Mayer --- .../files/downloader/DownloadNotificationManager.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 88c50e5fb3e9..f3c7cb0d5bc5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -102,14 +102,16 @@ class DownloadNotificationManager( val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) val text = String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) - updateNotificationText(text, false) + val title = + context.getString(R.string.downloader_download_in_progress_ticker) + updateNotificationText(title, text, false) } } @Suppress("MagicNumber") fun showCompleteNotification(text: String) { Handler(Looper.getMainLooper()).postDelayed({ - updateNotificationText(text, true) + updateNotificationText(null,text, true) dismissNotification() }, 3000) } @@ -126,17 +128,19 @@ class DownloadNotificationManager( notificationBuilder.run { setProgress(0, 0, false) + setContentTitle(null) setContentText(text) + setOngoing(false) notificationManager.notify(notifyId, this.build()) } } - private fun updateNotificationText(text: String, cancelProgressBar: Boolean) { + private fun updateNotificationText(title: String?, text: String, cancelProgressBar: Boolean) { notificationBuilder.run { if (cancelProgressBar) { setProgress(0, 0, false) } - + setContentTitle(title) setContentText(text) notificationManager.notify(id, this.build()) } From ef2ebb9176a354cc3448d22d82aad52d90b2576f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 10:07:58 +0100 Subject: [PATCH 088/189] Add long running task support Signed-off-by: alperozturk --- app/src/main/AndroidManifest.xml | 6 ++++++ .../files/downloader/DownloadNotificationManager.kt | 10 +++++++++- .../client/files/downloader/FileDownloadWorker.kt | 10 ++++++++++ .../com/nextcloud/utils/ForegroundServiceHelper.kt | 13 +++++++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f83f59ef32fd..4fda4a48604c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -239,6 +239,12 @@ android:exported="false" android:configChanges="orientation|screenLayout|screenSize|keyboardHidden" android:theme="@style/Theme.ownCloud.Media" /> + diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index f3c7cb0d5bc5..60ce0c1911b0 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -111,7 +111,7 @@ class DownloadNotificationManager( @Suppress("MagicNumber") fun showCompleteNotification(text: String) { Handler(Looper.getMainLooper()).postDelayed({ - updateNotificationText(null,text, true) + updateNotificationText(null, text, true) dismissNotification() }, 3000) } @@ -156,4 +156,12 @@ class DownloadNotificationManager( ) ) } + + fun getId(): Int { + return id + } + + fun getNotification(): Notification { + return notificationBuilder.build() + } } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index bf3c165f3df8..b4534cfa0a63 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -36,8 +36,10 @@ import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional import com.nextcloud.model.WorkerState import com.nextcloud.model.WorkerStateLiveData +import com.nextcloud.utils.ForegroundServiceHelper import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager +import com.owncloud.android.datamodel.ForegroundServiceType import com.owncloud.android.datamodel.OCFile import com.owncloud.android.files.services.IndexedForest import com.owncloud.android.lib.common.OwnCloudAccount @@ -123,6 +125,14 @@ class FileDownloadWorker( addAccountUpdateListener() + setForegroundAsync( + ForegroundServiceHelper.createWorkerForegroundInfo( + notificationManager.getId(), + notificationManager.getNotification(), + ForegroundServiceType.DataSync + ) + ) + requestDownloads.forEach { downloadFile(it) } diff --git a/app/src/main/java/com/nextcloud/utils/ForegroundServiceHelper.kt b/app/src/main/java/com/nextcloud/utils/ForegroundServiceHelper.kt index 9dd7d8008c22..9c9676679dcc 100644 --- a/app/src/main/java/com/nextcloud/utils/ForegroundServiceHelper.kt +++ b/app/src/main/java/com/nextcloud/utils/ForegroundServiceHelper.kt @@ -25,6 +25,7 @@ import android.app.Notification import android.app.Service import android.os.Build import androidx.core.app.ServiceCompat +import androidx.work.ForegroundInfo import com.owncloud.android.datamodel.ForegroundServiceType object ForegroundServiceHelper { @@ -45,4 +46,16 @@ object ForegroundServiceHelper { service.startForeground(id, notification) } } + + fun createWorkerForegroundInfo( + id: Int, + notification: Notification, + foregroundServiceType: ForegroundServiceType + ): ForegroundInfo { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + ForegroundInfo(id, notification, foregroundServiceType.getId()) + } else { + ForegroundInfo(id, notification) + } + } } From a0482e496d1ca2b1c24d89087f9ba7eff5a065cd Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 10:16:26 +0100 Subject: [PATCH 089/189] Improve notifications for different custom Android OS Signed-off-by: alperozturk --- .../client/files/downloader/DownloadNotificationManager.kt | 4 ++-- app/src/main/res/values/strings.xml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 60ce0c1911b0..1683ceade7fb 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -72,7 +72,7 @@ class DownloadNotificationManager( setProgress(100, 0, operation.size < 0) setContentText( String.format( - context.getString(R.string.downloader_download_in_progress_content), 0, + context.getString(R.string.downloader_download_in_progress), 0, File(operation.savePath).name ) ) @@ -101,7 +101,7 @@ class DownloadNotificationManager( setProgress(100, percent, totalToTransfer < 0) val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) val text = - String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) + String.format(context.getString(R.string.downloader_download_in_progress), percent, fileName) val title = context.getString(R.string.downloader_download_in_progress_ticker) updateNotificationText(title, text, false) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ddb012e5e173..fc427dd5516f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -169,6 +169,7 @@ %1$s (%2$d) Downloading… Downloads are completed + %1$d%% %2$s %1$d%% Downloading %2$s Downloaded %1$s downloaded From e1dc124a72d88b328f033570c8b18b651eabd424 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 12:49:58 +0100 Subject: [PATCH 090/189] Use fileId for notificationId Signed-off-by: alperozturk --- .../files/downloader/FileDownloadWorker.kt | 22 +++++++++++-------- .../client/jobs/BackgroundJobManagerImpl.kt | 2 ++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index b4534cfa0a63..4a26190830db 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -57,7 +57,7 @@ import java.util.Vector @Suppress("LongParameterList", "TooManyFunctions") class FileDownloadWorker( - viewThemeUtils: ViewThemeUtils, + private val viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, private var localBroadcastManager: LocalBroadcastManager, private val context: Context, @@ -75,6 +75,7 @@ class FileDownloadWorker( } } + const val WORKER_ID = "WORKER_ID" const val FILES_SEPARATOR = "," const val FOLDER_REMOTE_PATH = "FOLDER_REMOTE_PATH" const val FILE_REMOTE_PATH = "FILE_REMOTE_PATH" @@ -106,7 +107,7 @@ class FileDownloadWorker( private var lastPercent = 0 private val intents = FileDownloadIntents(context) - private val notificationManager = DownloadNotificationManager(SecureRandom().nextInt(), context, viewThemeUtils) + private lateinit var notificationManager: DownloadNotificationManager private var downloadProgressListener = FileDownloadProgressListener() private var user: User? = null @@ -115,6 +116,7 @@ class FileDownloadWorker( private var currentUserFileStorageManager: FileDataStorageManager? = null private var fileDataStorageManager: FileDataStorageManager? = null + private var workerId: Int? = null private var folder: OCFile? = null private var isAnyOperationFailed = false @@ -122,16 +124,17 @@ class FileDownloadWorker( override fun doWork(): Result { return try { val requestDownloads = getRequestDownloads() + notificationManager = + DownloadNotificationManager(workerId ?: SecureRandom().nextInt(), context, viewThemeUtils) addAccountUpdateListener() - setForegroundAsync( - ForegroundServiceHelper.createWorkerForegroundInfo( - notificationManager.getId(), - notificationManager.getNotification(), - ForegroundServiceType.DataSync - ) + val foregroundInfo = ForegroundServiceHelper.createWorkerForegroundInfo( + notificationManager.getId(), + notificationManager.getNotification(), + ForegroundServiceType.DataSync ) + setForegroundAsync(foregroundInfo) requestDownloads.forEach { downloadFile(it) @@ -199,6 +202,8 @@ class FileDownloadWorker( } private fun getRequestDownloads(): AbstractList { + workerId = inputData.keyValueMap[WORKER_ID] as Int + isAnyOperationFailed = false setUser() setFolder() @@ -206,7 +211,6 @@ class FileDownloadWorker( val downloadType = getDownloadType() conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? - val behaviour = inputData.keyValueMap[BEHAVIOUR] as String? ?: "" val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String? ?: "" val packageName = inputData.keyValueMap[PACKAGE_NAME] as String? ?: "" diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 948dc62eac06..fe667776f107 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -519,6 +519,7 @@ internal class BackgroundJobManagerImpl( override fun startFolderDownloadJob(folder: OCFile, user: User, filesPath: List) { val data = workDataOf( + FileDownloadWorker.WORKER_ID to folder.fileId.toInt(), FileDownloadWorker.ACCOUNT_NAME to user.accountName, FileDownloadWorker.FOLDER_REMOTE_PATH to folder.remotePath, FileDownloadWorker.FILES_REMOTE_PATH to filesPath.joinToString(FileDownloadWorker.FILES_SEPARATOR), @@ -548,6 +549,7 @@ internal class BackgroundJobManagerImpl( val tag = startFileDownloadJobTag(user, file.fileId) val data = workDataOf( + FileDownloadWorker.WORKER_ID to file.fileId.toInt(), FileDownloadWorker.ACCOUNT_NAME to user.accountName, FileDownloadWorker.FILE_REMOTE_PATH to file.remotePath, FileDownloadWorker.BEHAVIOUR to behaviour, From 4209c489459a12ffe5332f16a4240a845070278c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 12:55:29 +0100 Subject: [PATCH 091/189] Rebase master Signed-off-by: alperozturk --- .../client/files/downloader/DownloadWorker.kt | 39 + .../files/services/FileDownloader.java | 702 ++++++++++++++++++ 2 files changed, 741 insertions(+) create mode 100644 app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt create mode 100644 app/src/main/java/com/owncloud/android/files/services/FileDownloader.java diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt new file mode 100644 index 000000000000..70cfe01e674a --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt @@ -0,0 +1,39 @@ +/* + * 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 . + */ + +package com.nextcloud.client.files.downloader + +import android.content.Context +import android.content.Intent +import androidx.work.Worker +import androidx.work.WorkerParameters +import com.owncloud.android.files.services.FileDownloader + +class DownloadWorker( + private val context: Context, + params: WorkerParameters, + private val intent: Intent, + private val fileDownloader: FileDownloader, +) : Worker(context, params) { + override fun doWork(): Result { + TODO("Not yet implemented") + } +} diff --git a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java new file mode 100644 index 000000000000..d0db5d7761ad --- /dev/null +++ b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java @@ -0,0 +1,702 @@ +/* + * ownCloud Android client application + * + * Copyright (C) 2012 Bartek Przybylski + * Copyright (C) 2012-2016 ownCloud Inc. + * + * 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.files.services; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.OnAccountsUpdateListener; +import android.app.Activity; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.graphics.BitmapFactory; +import android.os.Binder; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.Process; +import android.util.Pair; + +import com.nextcloud.client.account.User; +import com.nextcloud.client.account.UserAccountManager; +import com.nextcloud.client.files.downloader.DownloadTask; +import com.nextcloud.java.util.Optional; +import com.nextcloud.utils.ForegroundServiceHelper; +import com.nextcloud.utils.extensions.IntentExtensionsKt; +import com.owncloud.android.R; +import com.owncloud.android.authentication.AuthenticatorActivity; +import com.owncloud.android.datamodel.FileDataStorageManager; +import com.owncloud.android.datamodel.ForegroundServiceType; +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.datamodel.UploadsStorageManager; +import com.owncloud.android.lib.common.OwnCloudAccount; +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; +import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; +import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.lib.resources.files.FileUtils; +import com.owncloud.android.operations.DownloadFileOperation; +import com.owncloud.android.operations.DownloadType; +import com.owncloud.android.providers.DocumentsStorageProvider; +import com.owncloud.android.ui.activity.ConflictsResolveActivity; +import com.owncloud.android.ui.activity.FileActivity; +import com.owncloud.android.ui.activity.FileDisplayActivity; +import com.owncloud.android.ui.dialog.SendShareDialog; +import com.owncloud.android.ui.fragment.OCFileListFragment; +import com.owncloud.android.ui.notifications.NotificationUtils; +import com.owncloud.android.ui.preview.PreviewImageActivity; +import com.owncloud.android.ui.preview.PreviewImageFragment; +import com.owncloud.android.utils.ErrorMessageAdapter; +import com.owncloud.android.utils.MimeTypeUtil; +import com.owncloud.android.utils.theme.ViewThemeUtils; + +import java.io.File; +import java.security.SecureRandom; +import java.util.AbstractList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Vector; + +import javax.inject.Inject; + +import androidx.core.app.NotificationCompat; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import dagger.android.AndroidInjection; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + +import static android.content.Context.NOTIFICATION_SERVICE; + +public class FileDownloader implements OnDatatransferProgressListener, OnAccountsUpdateListener { + + private final Activity activity; + private final Intent intent; + private final int startId; + + public static final String EXTRA_USER = "USER"; + public static final String EXTRA_FILE = "FILE"; + + private static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED"; + private static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH"; + public static final String EXTRA_DOWNLOAD_RESULT = "RESULT"; + public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; + public static final String EXTRA_LINKED_TO_PATH = "LINKED_TO"; + public static final String ACCOUNT_NAME = "ACCOUNT_NAME"; + public static final String DOWNLOAD_TYPE = "DOWNLOAD_TYPE"; + + private static final int FOREGROUND_SERVICE_ID = 412; + + private static final String TAG = FileDownloader.class.getSimpleName(); + + private Looper mServiceLooper; + private ServiceHandler mServiceHandler; + private IBinder mBinder; + private OwnCloudClient mDownloadClient; + private Optional currentUser = Optional.empty(); + private FileDataStorageManager mStorageManager; + + private IndexedForest mPendingDownloads = new IndexedForest<>(); + + private DownloadFileOperation mCurrentDownload; + + private NotificationManager mNotificationManager; + private NotificationCompat.Builder mNotificationBuilder; + private int mLastPercent; + + private Notification mNotification; + + private long conflictUploadId; + + public boolean mStartedDownload = false; + + @Inject UserAccountManager accountManager; + @Inject UploadsStorageManager uploadsStorageManager; + @Inject LocalBroadcastManager localBroadcastManager; + @Inject ViewThemeUtils viewThemeUtils; + + public static String getDownloadAddedMessage() { + return FileDownloader.class.getName() + DOWNLOAD_ADDED_MESSAGE; + } + + public static String getDownloadFinishMessage() { + return FileDownloader.class.getName() + DOWNLOAD_FINISH_MESSAGE; + } + + public FileDownloader(Activity activity, Intent intent, int startId) { + this.activity = activity; + this.intent = intent; + this.startId = startId; + + AndroidInjection.inject(activity); + Log_OC.d(TAG, "Creating service"); + mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); + HandlerThread thread = new HandlerThread("FileDownloaderThread", Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + mServiceLooper = thread.getLooper(); + mServiceHandler = new ServiceHandler(mServiceLooper, this); + mBinder = new FileDownloaderBinder(); + + NotificationCompat.Builder builder = NotificationUtils.newNotificationBuilder(activity, viewThemeUtils).setContentTitle( + activity.getResources().getString(R.string.app_name)) + .setContentText(activity.getResources().getString(R.string.foreground_service_download)) + .setSmallIcon(R.drawable.notification_icon) + .setLargeIcon(BitmapFactory.decodeResource(activity.getResources(), R.drawable.notification_icon)); + + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + builder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD); + } + + mNotification = builder.build(); + + // add AccountsUpdatedListener + AccountManager am = AccountManager.get(activity); + am.addOnAccountsUpdatedListener(this, null, false); + } + + + @Override + protected void finalize() throws Throwable { + Log_OC.v(TAG, "Destroying service"); + mBinder = null; + mServiceHandler = null; + mServiceLooper.quit(); + mServiceLooper = null; + mNotificationManager = null; + + // remove AccountsUpdatedListener + AccountManager am = AccountManager.get(activity); + am.removeOnAccountsUpdatedListener(this); + super.finalize(); + } + + public void download() { + final User user = IntentExtensionsKt.getParcelableArgument(intent, EXTRA_USER, User.class); + final OCFile file = IntentExtensionsKt.getParcelableArgument(intent, EXTRA_FILE, OCFile.class); + final String behaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); + + DownloadType downloadType = DownloadType.DOWNLOAD; + if (intent.hasExtra(DOWNLOAD_TYPE)) { + downloadType = IntentExtensionsKt.getSerializableArgument(intent, DOWNLOAD_TYPE, DownloadType.class); + } + String activityName = intent.getStringExtra(SendShareDialog.ACTIVITY_NAME); + String packageName = intent.getStringExtra(SendShareDialog.PACKAGE_NAME); + conflictUploadId = intent.getLongExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, -1); + AbstractList requestedDownloads = new Vector(); + try { + DownloadFileOperation newDownload = new DownloadFileOperation(user, + file, + behaviour, + activityName, + packageName, + activity, + downloadType); + newDownload.addDatatransferProgressListener(this); + newDownload.addDatatransferProgressListener((FileDownloaderBinder) mBinder); + Pair putResult = mPendingDownloads.putIfAbsent(user.getAccountName(), + file.getRemotePath(), + newDownload); + if (putResult != null) { + String downloadKey = putResult.first; + requestedDownloads.add(downloadKey); + sendBroadcastNewDownload(newDownload, putResult.second); + } // else, file already in the queue of downloads; don't repeat the request + + } catch (IllegalArgumentException e) { + Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage()); + } + + if (requestedDownloads.size() > 0) { + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = startId; + msg.obj = requestedDownloads; + mServiceHandler.sendMessage(msg); + } + } + + @Override + public void onAccountsUpdated(Account[] accounts) { + //review the current download and cancel it if its account doesn't exist + if (mCurrentDownload != null && !accountManager.exists(mCurrentDownload.getUser().toPlatformAccount())) { + mCurrentDownload.cancel(); + } + // The rest of downloads are cancelled when they try to start + } + + + /** + * Binder to let client components to perform operations on the queue of downloads. + *

+ * It provides by itself the available operations. + */ + public class FileDownloaderBinder extends Binder implements OnDatatransferProgressListener { + + /** + * Map of listeners that will be reported about progress of downloads from a + * {@link FileDownloaderBinder} + * instance. + */ + private Map mBoundListeners = + new HashMap(); + + + /** + * Cancels a pending or current download of a remote file. + * + * @param account ownCloud account where the remote file is stored. + * @param file A file in the queue of pending downloads + */ + public void cancel(Account account, OCFile file) { + Pair removeResult = + mPendingDownloads.remove(account.name, file.getRemotePath()); + DownloadFileOperation download = removeResult.first; + if (download != null) { + download.cancel(); + } else { + if (mCurrentDownload != null && currentUser.isPresent() && + mCurrentDownload.getRemotePath().startsWith(file.getRemotePath()) && + account.name.equals(currentUser.get().getAccountName())) { + mCurrentDownload.cancel(); + } + } + } + + /** + * Cancels all the downloads for an account + */ + public void cancel(String accountName) { + if (mCurrentDownload != null && mCurrentDownload.getUser().nameEquals(accountName)) { + mCurrentDownload.cancel(); + } + // Cancel pending downloads + cancelPendingDownloads(accountName); + } + + public void clearListeners() { + mBoundListeners.clear(); + } + + + /** + * Returns True when the file described by 'file' in the ownCloud account 'account' + * is downloading or waiting to download. + * + * If 'file' is a directory, returns 'true' if any of its descendant files is downloading or + * waiting to download. + * + * @param user user where the remote file is stored. + * @param file A file that could be in the queue of downloads. + */ + public boolean isDownloading(User user, OCFile file) { + return user != null && file != null && mPendingDownloads.contains(user.getAccountName(), file.getRemotePath()); + } + + + /** + * Adds a listener interested in the progress of the download for a concrete file. + * + * @param listener Object to notify about progress of transfer. + * @param file {@link OCFile} of interest for listener. + */ + public void addDatatransferProgressListener(OnDatatransferProgressListener listener, OCFile file) { + if (file == null || listener == null) { + return; + } + mBoundListeners.put(file.getFileId(), listener); + } + + + /** + * Removes a listener interested in the progress of the download for a concrete file. + * + * @param listener Object to notify about progress of transfer. + * @param file {@link OCFile} of interest for listener. + */ + public void removeDatatransferProgressListener(OnDatatransferProgressListener listener, OCFile file) { + if (file == null || listener == null) { + return; + } + Long fileId = file.getFileId(); + if (mBoundListeners.get(fileId) == listener) { + mBoundListeners.remove(fileId); + } + } + + @Override + public void onTransferProgress(long progressRate, long totalTransferredSoFar, + long totalToTransfer, String fileName) { + OnDatatransferProgressListener boundListener = + mBoundListeners.get(mCurrentDownload.getFile().getFileId()); + if (boundListener != null) { + boundListener.onTransferProgress(progressRate, totalTransferredSoFar, + totalToTransfer, fileName); + } + } + + } + + /** + * Download worker. Performs the pending downloads in the order they were requested. + + * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}. + */ + private static class ServiceHandler extends Handler { + // don't make it a final class, and don't remove the static ; lint will warn about a + // possible memory leak + FileDownloader mService; + + public ServiceHandler(Looper looper, FileDownloader service) { + super(looper); + if (service == null) { + throw new IllegalArgumentException("Received invalid NULL in parameter 'service'"); + } + mService = service; + } + + @Override + public void handleMessage(Message msg) { + @SuppressWarnings("unchecked") + AbstractList requestedDownloads = (AbstractList) msg.obj; + if (msg.obj != null) { + Iterator it = requestedDownloads.iterator(); + while (it.hasNext()) { + String next = it.next(); + mService.downloadFile(next); + } + } + mService.mStartedDownload=false; + + (new Handler()).postDelayed(() -> { + if(!mService.mStartedDownload){ + mService.mNotificationManager.cancel(R.string.downloader_download_in_progress_ticker); + } + Log_OC.d(TAG, "Stopping after command with id " + msg.arg1); + mService.mNotificationManager.cancel(FOREGROUND_SERVICE_ID); + }, 2000); + } + } + + + /** + * Core download method: requests a file to download and stores it. + * + * @param downloadKey Key to access the download to perform, contained in mPendingDownloads + */ + private void downloadFile(String downloadKey) { + + mStartedDownload = true; + mCurrentDownload = mPendingDownloads.get(downloadKey); + + if (mCurrentDownload != null) { + // Detect if the account exists + if (accountManager.exists(mCurrentDownload.getUser().toPlatformAccount())) { + notifyDownloadStart(mCurrentDownload); + RemoteOperationResult downloadResult = null; + try { + /// prepare client object to send the request to the ownCloud server + Account currentDownloadAccount = mCurrentDownload.getUser().toPlatformAccount(); + Optional currentDownloadUser = accountManager.getUser(currentDownloadAccount.name); + if (!currentUser.equals(currentDownloadUser)) { + currentUser = currentDownloadUser; + mStorageManager = new FileDataStorageManager(currentUser.get(), activity.getContentResolver()); + } // else, reuse storage manager from previous operation + + // always get client from client manager, to get fresh credentials in case + // of update + OwnCloudAccount ocAccount = currentDownloadUser.get().toOwnCloudAccount(); + mDownloadClient = OwnCloudClientManagerFactory.getDefaultSingleton(). + getClientFor(ocAccount, activity); + + + /// perform the download + downloadResult = mCurrentDownload.execute(mDownloadClient); + if (downloadResult.isSuccess() && mCurrentDownload.getDownloadType() == DownloadType.DOWNLOAD) { + saveDownloadedFile(); + } + + } catch (Exception e) { + Log_OC.e(TAG, "Error downloading", e); + downloadResult = new RemoteOperationResult(e); + + } finally { + Pair removeResult = mPendingDownloads.removePayload( + mCurrentDownload.getUser().getAccountName(), mCurrentDownload.getRemotePath()); + + if (downloadResult == null) { + downloadResult = new RemoteOperationResult(new RuntimeException("Error downloading…")); + } + + /// notify result + notifyDownloadResult(mCurrentDownload, downloadResult); + sendBroadcastDownloadFinished(mCurrentDownload, downloadResult, removeResult.second); + } + } else { + cancelPendingDownloads(mCurrentDownload.getUser().getAccountName()); + } + } + } + + + /** + * Updates the OC File after a successful download. + * + * TODO move to DownloadFileOperation + * unify with code from {@link DocumentsStorageProvider} and {@link DownloadTask}. + */ + private void saveDownloadedFile() { + OCFile file = mStorageManager.getFileById(mCurrentDownload.getFile().getFileId()); + + if (file == null) { + // try to get file via path, needed for overwriting existing files on conflict dialog + file = mStorageManager.getFileByDecryptedRemotePath(mCurrentDownload.getFile().getRemotePath()); + } + + if (file == null) { + Log_OC.e(this, "Could not save " + mCurrentDownload.getFile().getRemotePath()); + return; + } + + long syncDate = System.currentTimeMillis(); + file.setLastSyncDateForProperties(syncDate); + file.setLastSyncDateForData(syncDate); + file.setUpdateThumbnailNeeded(true); + file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp()); + file.setModificationTimestampAtLastSyncForData(mCurrentDownload.getModificationTimestamp()); + file.setEtag(mCurrentDownload.getEtag()); + file.setMimeType(mCurrentDownload.getMimeType()); + file.setStoragePath(mCurrentDownload.getSavePath()); + file.setFileLength(new File(mCurrentDownload.getSavePath()).length()); + file.setRemoteId(mCurrentDownload.getFile().getRemoteId()); + mStorageManager.saveFile(file); + if (MimeTypeUtil.isMedia(mCurrentDownload.getMimeType())) { + FileDataStorageManager.triggerMediaScan(file.getStoragePath(), file); + } + mStorageManager.saveConflict(file, null); + } + + /** + * Creates a status notification to show the download progress + * + * @param download Download operation starting. + */ + private void notifyDownloadStart(DownloadFileOperation download) { + /// create status notification with a progress bar + mLastPercent = 0; + mNotificationBuilder = NotificationUtils.newNotificationBuilder(activity, viewThemeUtils); + mNotificationBuilder + .setSmallIcon(R.drawable.notification_icon) + .setTicker(activity.getString(R.string.downloader_download_in_progress_ticker)) + .setContentTitle(activity.getString(R.string.downloader_download_in_progress_ticker)) + .setOngoing(true) + .setProgress(100, 0, download.getSize() < 0) + .setContentText( + String.format(activity.getString(R.string.downloader_download_in_progress_content), 0, + new File(download.getSavePath()).getName())); + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + mNotificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD); + } + + /// includes a pending intent in the notification showing the details view of the file + Intent showDetailsIntent = null; + if (PreviewImageFragment.canBePreviewed(download.getFile())) { + showDetailsIntent = new Intent(activity, PreviewImageActivity.class); + } else { + showDetailsIntent = new Intent(activity, FileDisplayActivity.class); + } + showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, download.getFile()); + showDetailsIntent.putExtra(FileActivity.EXTRA_USER, download.getUser()); + showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + + mNotificationBuilder.setContentIntent(PendingIntent.getActivity(activity, (int) System.currentTimeMillis(), + showDetailsIntent, PendingIntent.FLAG_IMMUTABLE)); + + + if (mNotificationManager == null) { + mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); + } + if (mNotificationManager != null) { + mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotificationBuilder.build()); + } + } + + + /** + * Callback method to update the progress bar in the status notification. + */ + @Override + public void onTransferProgress(long progressRate, long totalTransferredSoFar, + long totalToTransfer, String filePath) { + int percent = (int) (100.0 * ((double) totalTransferredSoFar) / ((double) totalToTransfer)); + if (percent != mLastPercent) { + mNotificationBuilder.setProgress(100, percent, totalToTransfer < 0); + String fileName = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1); + String text = String.format(activity.getString(R.string.downloader_download_in_progress_content), percent, fileName); + mNotificationBuilder.setContentText(text); + + if (mNotificationManager == null) { + mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); + } + + if (mNotificationManager != null) { + mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, + mNotificationBuilder.build()); + } + } + mLastPercent = percent; + } + + + /** + * Updates the status notification with the result of a download operation. + * + * @param downloadResult Result of the download operation. + * @param download Finished download operation + */ + @SuppressFBWarnings("DMI") + private void notifyDownloadResult(DownloadFileOperation download, + RemoteOperationResult downloadResult) { + if (mNotificationManager == null) { + mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); + } + + if (!downloadResult.isCancelled()) { + if (downloadResult.isSuccess()) { + if (conflictUploadId > 0) { + uploadsStorageManager.removeUpload(conflictUploadId); + } + // Dont show notification except an error has occured. + return; + } + int tickerId = downloadResult.isSuccess() ? + R.string.downloader_download_succeeded_ticker : R.string.downloader_download_failed_ticker; + + boolean needsToUpdateCredentials = ResultCode.UNAUTHORIZED == downloadResult.getCode(); + tickerId = needsToUpdateCredentials ? + R.string.downloader_download_failed_credentials_error : tickerId; + + mNotificationBuilder + .setTicker(activity.getString(tickerId)) + .setContentTitle(activity.getString(tickerId)) + .setAutoCancel(true) + .setOngoing(false) + .setProgress(0, 0, false); + + if (needsToUpdateCredentials) { + configureUpdateCredentialsNotification(download.getUser()); + + } else { + // TODO put something smart in showDetailsIntent + Intent showDetailsIntent = new Intent(); + mNotificationBuilder.setContentIntent(PendingIntent.getActivity(activity, (int) System.currentTimeMillis(), + showDetailsIntent, PendingIntent.FLAG_IMMUTABLE)); + } + + mNotificationBuilder.setContentText(ErrorMessageAdapter.getErrorCauseMessage(downloadResult, + download, activity.getResources())); + + if (mNotificationManager != null) { + mNotificationManager.notify((new SecureRandom()).nextInt(), mNotificationBuilder.build()); + + // Remove success notification + if (downloadResult.isSuccess()) { + // Sleep 2 seconds, so show the notification before remove it + NotificationUtils.cancelWithDelay(mNotificationManager, + R.string.downloader_download_succeeded_ticker, 2000); + } + } + } + } + + private void configureUpdateCredentialsNotification(User user) { + // let the user update credentials with one click + Intent updateAccountCredentials = new Intent(activity, AuthenticatorActivity.class); + updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()); + updateAccountCredentials.putExtra( + AuthenticatorActivity.EXTRA_ACTION, + AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN + ); + updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND); + mNotificationBuilder.setContentIntent( + PendingIntent.getActivity(activity, + (int) System.currentTimeMillis(), + updateAccountCredentials, + PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE) + ); + } + + + /** + * Sends a broadcast when a download finishes in order to the interested activities can + * update their view + * + * @param download Finished download operation + * @param downloadResult Result of the download operation + * @param unlinkedFromRemotePath Path in the downloads tree where the download was unlinked from + */ + private void sendBroadcastDownloadFinished( + DownloadFileOperation download, + RemoteOperationResult downloadResult, + String unlinkedFromRemotePath) { + + Intent end = new Intent(getDownloadFinishMessage()); + end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess()); + end.putExtra(ACCOUNT_NAME, download.getUser().getAccountName()); + end.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath()); + end.putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.getBehaviour()); + end.putExtra(SendShareDialog.ACTIVITY_NAME, download.getActivityName()); + end.putExtra(SendShareDialog.PACKAGE_NAME, download.getPackageName()); + if (unlinkedFromRemotePath != null) { + end.putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath); + } + end.setPackage(activity.getPackageName()); + localBroadcastManager.sendBroadcast(end); + } + + + /** + * Sends a broadcast when a new download is added to the queue. + * + * @param download Added download operation + * @param linkedToRemotePath Path in the downloads tree where the download was linked to + */ + private void sendBroadcastNewDownload(DownloadFileOperation download, + String linkedToRemotePath) { + Intent added = new Intent(getDownloadAddedMessage()); + added.putExtra(ACCOUNT_NAME, download.getUser().getAccountName()); + added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath()); + added.putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath); + added.setPackage(activity.getPackageName()); + localBroadcastManager.sendBroadcast(added); + } + + private void cancelPendingDownloads(String accountName) { + mPendingDownloads.remove(accountName); + } +} From a2a1ce4f23ab7392796f017826345779e655f986 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 12:55:41 +0100 Subject: [PATCH 092/189] Rebase master Signed-off-by: alperozturk --- app/src/main/AndroidManifest.xml | 8 +- .../nextcloud/client/di/ComponentsModule.java | 2 + ...wnloadWorker.kt => FilesDownloadWorker.kt} | 33 +++++-- .../client/jobs/BackgroundJobFactory.kt | 9 +- .../client/jobs/BackgroundJobManager.kt | 19 +--- .../client/jobs/BackgroundJobManagerImpl.kt | 68 ++++----------- .../nextcloud/client/jobs/FilesExportWork.kt | 16 ++-- .../files/services/FileDownloader.java | 87 ++++++++----------- .../operations/SynchronizeFileOperation.java | 19 +++- .../ui/activity/ConflictsResolveActivity.kt | 15 ++-- .../android/ui/activity/FileActivity.java | 24 +++-- .../ui/preview/PreviewImageActivity.java | 72 +++++++-------- .../ui/preview/PreviewMediaFragment.java | 9 +- 13 files changed, 183 insertions(+), 198 deletions(-) rename app/src/main/java/com/nextcloud/client/files/downloader/{DownloadWorker.kt => FilesDownloadWorker.kt} (52%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4fda4a48604c..3d9cb464745e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -239,12 +239,6 @@ android:exported="false" android:configChanges="orientation|screenLayout|screenSize|keyboardHidden" android:theme="@style/Theme.ownCloud.Media" /> - @@ -400,7 +394,7 @@ android:name=".services.OperationsService" android:exported="false" /> createCalendarImportWork(context, workerParameters) FilesExportWork::class -> createFilesExportWork(context, workerParameters) FilesUploadWorker::class -> createFilesUploadWorker(context, workerParameters) - FileDownloadWorker::class -> createFilesDownloadWorker(context, workerParameters) + FilesDownloadWorker::class -> createFilesDownloadWorker(context, workerParameters) GeneratePdfFromImagesWork::class -> createPDFGenerateWork(context, workerParameters) HealthStatusWork::class -> createHealthStatusWork(context, workerParameters) TestJob::class -> createTestJob(context, workerParameters) @@ -255,10 +255,11 @@ class BackgroundJobFactory @Inject constructor( ) } - private fun createFilesDownloadWorker(context: Context, params: WorkerParameters): FileDownloadWorker { - return FileDownloadWorker( + private fun createFilesDownloadWorker(context: Context, params: WorkerParameters): FilesDownloadWorker { + return FilesDownloadWorker( viewThemeUtils.get(), accountManager, + uploadsStorageManager, localBroadcastManager.get(), context, params diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 9fc2879be6b3..fbcc04922e17 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -145,25 +145,14 @@ interface BackgroundJobManager { fun getFileUploads(user: User): LiveData> fun cancelFilesUploadJob(user: User) - fun cancelFilesDownloadJob(user: User, fileId: Long) - - fun isStartFileDownloadJobScheduled(user: User, fileId: Long): Boolean - - @Suppress("LongParameterList") - fun startFileDownloadJob( + fun startFilesDownloadJob( user: User, - file: OCFile, + ocFile: OCFile, behaviour: String, - downloadType: DownloadType?, + downloadType: DownloadType, activityName: String, packageName: String, - conflictUploadId: Long? - ) - - fun startFolderDownloadJob( - folder: OCFile, - user: User, - filesPath: List + conflictUploadId: Long ) fun startPdfGenerateAndUploadWork(user: User, uploadFolder: String, imagePaths: List, pdfPath: String) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index fe667776f107..d291189269de 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -38,11 +38,11 @@ import com.nextcloud.client.account.User import com.nextcloud.client.core.Clock import com.nextcloud.client.di.Injectable import com.nextcloud.client.documentscan.GeneratePdfFromImagesWork -import com.nextcloud.client.files.downloader.FileDownloadWorker +import com.nextcloud.client.files.downloader.FilesDownloadWorker import com.nextcloud.client.preferences.AppPreferences -import com.nextcloud.utils.extensions.isWorkScheduled import com.owncloud.android.datamodel.OCFile import com.owncloud.android.operations.DownloadType +import java.io.File import java.util.Date import java.util.UUID import java.util.concurrent.TimeUnit @@ -86,7 +86,6 @@ internal class BackgroundJobManagerImpl( const val JOB_NOTIFICATION = "notification" const val JOB_ACCOUNT_REMOVAL = "account_removal" const val JOB_FILES_UPLOAD = "files_upload" - const val JOB_FOLDER_DOWNLOAD = "folder_download" const val JOB_FILES_DOWNLOAD = "files_download" const val JOB_PDF_GENERATION = "pdf_generation" const val JOB_IMMEDIATE_CALENDAR_BACKUP = "immediate_calendar_backup" @@ -499,6 +498,7 @@ internal class BackgroundJobManagerImpl( workManager.enqueue(request) } + override fun startFilesUploadJob(user: User) { val data = workDataOf(FilesUploadWorker.ACCOUNT to user.accountName) @@ -509,62 +509,30 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_FILES_UPLOAD + user.accountName, ExistingWorkPolicy.KEEP, request) } - private fun startFileDownloadJobTag(user: User, fileId: Long): String { - return JOB_FOLDER_DOWNLOAD + user.accountName + fileId - } - - override fun isStartFileDownloadJobScheduled(user: User, fileId: Long): Boolean { - return workManager.isWorkScheduled(startFileDownloadJobTag(user, fileId)) - } - - override fun startFolderDownloadJob(folder: OCFile, user: User, filesPath: List) { - val data = workDataOf( - FileDownloadWorker.WORKER_ID to folder.fileId.toInt(), - FileDownloadWorker.ACCOUNT_NAME to user.accountName, - FileDownloadWorker.FOLDER_REMOTE_PATH to folder.remotePath, - FileDownloadWorker.FILES_REMOTE_PATH to filesPath.joinToString(FileDownloadWorker.FILES_SEPARATOR), - FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() - ) - - val tag = startFileDownloadJobTag(user, folder.fileId) - - val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) - .addTag(tag) - .setInputData(data) - .build() - - workManager - .enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) - } - - override fun startFileDownloadJob( + override fun startFilesDownloadJob( user: User, - file: OCFile, + ocFile: OCFile, behaviour: String, - downloadType: DownloadType?, + downloadType: DownloadType, activityName: String, packageName: String, - conflictUploadId: Long? + conflictUploadId: Long ) { - val tag = startFileDownloadJobTag(user, file.fileId) - val data = workDataOf( - FileDownloadWorker.WORKER_ID to file.fileId.toInt(), - FileDownloadWorker.ACCOUNT_NAME to user.accountName, - FileDownloadWorker.FILE_REMOTE_PATH to file.remotePath, - FileDownloadWorker.BEHAVIOUR to behaviour, - FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), - FileDownloadWorker.ACTIVITY_NAME to activityName, - FileDownloadWorker.PACKAGE_NAME to packageName, - FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId + FilesDownloadWorker.USER to user, + FilesDownloadWorker.FILE to ocFile, + FilesDownloadWorker.BEHAVIOUR to behaviour, + FilesDownloadWorker.DOWNLOAD_TYPE to downloadType, + FilesDownloadWorker.ACTIVITY_NAME to activityName, + FilesDownloadWorker.PACKAGE_NAME to packageName, + FilesDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId, ) - val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) - .addTag(tag) + val request = oneTimeRequestBuilder(FilesDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .setInputData(data) .build() - workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) + workManager.enqueueUniqueWork(JOB_FILES_DOWNLOAD + user.accountName, ExistingWorkPolicy.REPLACE, request) } override fun getFileUploads(user: User): LiveData> { @@ -576,10 +544,6 @@ internal class BackgroundJobManagerImpl( workManager.cancelJob(JOB_FILES_UPLOAD, user) } - override fun cancelFilesDownloadJob(user: User, fileId: Long) { - workManager.cancelAllWorkByTag(startFileDownloadJobTag(user, fileId)) - } - override fun startPdfGenerateAndUploadWork( user: User, uploadFolder: String, diff --git a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt index 05586ba96569..cb8172655ccf 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt @@ -33,12 +33,13 @@ import androidx.core.app.NotificationCompat import androidx.work.Worker import androidx.work.WorkerParameters import com.nextcloud.client.account.User -import com.nextcloud.client.files.downloader.FileDownloadHelper import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.files.services.FileDownloader import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.operations.DownloadType +import com.owncloud.android.ui.dialog.SendShareDialog import com.owncloud.android.ui.notifications.NotificationUtils import com.owncloud.android.utils.FileExportUtils import com.owncloud.android.utils.FileStorageUtils @@ -111,11 +112,14 @@ class FilesExportWork( } private fun downloadFile(ocFile: OCFile) { - FileDownloadHelper.instance().downloadFile( - user, - ocFile, - downloadType = DownloadType.EXPORT - ) + val i = Intent(appContext, FileDownloader::class.java) + i.putExtra(FileDownloader.EXTRA_USER, user) + i.putExtra(FileDownloader.EXTRA_FILE, ocFile) + i.putExtra(SendShareDialog.PACKAGE_NAME, "") + i.putExtra(SendShareDialog.ACTIVITY_NAME, "") + i.putExtra(FileDownloader.DOWNLOAD_TYPE, DownloadType.EXPORT) + + FileDownloader(i) } private fun showErrorNotification(successfulExports: Int) { diff --git a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java index d0db5d7761ad..a528d479ffe1 100644 --- a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java +++ b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java @@ -23,11 +23,10 @@ import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.OnAccountsUpdateListener; -import android.app.Activity; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; -import android.app.Service; +import android.content.Context; import android.content.Intent; import android.graphics.BitmapFactory; import android.os.Binder; @@ -42,13 +41,13 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.files.downloader.DownloadTask; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.java.util.Optional; -import com.nextcloud.utils.ForegroundServiceHelper; import com.nextcloud.utils.extensions.IntentExtensionsKt; +import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.authentication.AuthenticatorActivity; import com.owncloud.android.datamodel.FileDataStorageManager; -import com.owncloud.android.datamodel.ForegroundServiceType; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.UploadsStorageManager; import com.owncloud.android.lib.common.OwnCloudAccount; @@ -86,16 +85,17 @@ import androidx.core.app.NotificationCompat; import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import dagger.android.AndroidInjection; +import androidx.work.OneTimeWorkRequest; +import androidx.work.WorkManager; +import androidx.work.WorkRequest; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import static android.content.Context.NOTIFICATION_SERVICE; public class FileDownloader implements OnDatatransferProgressListener, OnAccountsUpdateListener { - private final Activity activity; + private final Context context = MainApp.getAppContext(); private final Intent intent; - private final int startId; public static final String EXTRA_USER = "USER"; public static final String EXTRA_FILE = "FILE"; @@ -146,25 +146,21 @@ public static String getDownloadFinishMessage() { return FileDownloader.class.getName() + DOWNLOAD_FINISH_MESSAGE; } - public FileDownloader(Activity activity, Intent intent, int startId) { - this.activity = activity; + public FileDownloader(Intent intent) { this.intent = intent; - this.startId = startId; - - AndroidInjection.inject(activity); Log_OC.d(TAG, "Creating service"); - mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); + mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); HandlerThread thread = new HandlerThread("FileDownloaderThread", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper, this); mBinder = new FileDownloaderBinder(); - NotificationCompat.Builder builder = NotificationUtils.newNotificationBuilder(activity, viewThemeUtils).setContentTitle( - activity.getResources().getString(R.string.app_name)) - .setContentText(activity.getResources().getString(R.string.foreground_service_download)) + NotificationCompat.Builder builder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).setContentTitle( + context.getResources().getString(R.string.app_name)) + .setContentText(context.getResources().getString(R.string.foreground_service_download)) .setSmallIcon(R.drawable.notification_icon) - .setLargeIcon(BitmapFactory.decodeResource(activity.getResources(), R.drawable.notification_icon)); + .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.notification_icon)); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { @@ -174,11 +170,10 @@ public FileDownloader(Activity activity, Intent intent, int startId) { mNotification = builder.build(); // add AccountsUpdatedListener - AccountManager am = AccountManager.get(activity); + AccountManager am = AccountManager.get(context); am.addOnAccountsUpdatedListener(this, null, false); } - @Override protected void finalize() throws Throwable { Log_OC.v(TAG, "Destroying service"); @@ -189,7 +184,7 @@ protected void finalize() throws Throwable { mNotificationManager = null; // remove AccountsUpdatedListener - AccountManager am = AccountManager.get(activity); + AccountManager am = AccountManager.get(context); am.removeOnAccountsUpdatedListener(this); super.finalize(); } @@ -213,7 +208,7 @@ public void download() { behaviour, activityName, packageName, - activity, + context, downloadType); newDownload.addDatatransferProgressListener(this); newDownload.addDatatransferProgressListener((FileDownloaderBinder) mBinder); @@ -232,7 +227,7 @@ public void download() { if (requestedDownloads.size() > 0) { Message msg = mServiceHandler.obtainMessage(); - msg.arg1 = startId; + // msg.arg1 = startId; msg.obj = requestedDownloads; mServiceHandler.sendMessage(msg); } @@ -247,7 +242,6 @@ public void onAccountsUpdated(Account[] accounts) { // The rest of downloads are cancelled when they try to start } - /** * Binder to let client components to perform operations on the queue of downloads. *

@@ -296,11 +290,6 @@ public void cancel(String accountName) { cancelPendingDownloads(accountName); } - public void clearListeners() { - mBoundListeners.clear(); - } - - /** * Returns True when the file described by 'file' in the ownCloud account 'account' * is downloading or waiting to download. @@ -422,14 +411,14 @@ private void downloadFile(String downloadKey) { Optional currentDownloadUser = accountManager.getUser(currentDownloadAccount.name); if (!currentUser.equals(currentDownloadUser)) { currentUser = currentDownloadUser; - mStorageManager = new FileDataStorageManager(currentUser.get(), activity.getContentResolver()); + mStorageManager = new FileDataStorageManager(currentUser.get(), context.getContentResolver()); } // else, reuse storage manager from previous operation // always get client from client manager, to get fresh credentials in case // of update OwnCloudAccount ocAccount = currentDownloadUser.get().toOwnCloudAccount(); mDownloadClient = OwnCloudClientManagerFactory.getDefaultSingleton(). - getClientFor(ocAccount, activity); + getClientFor(ocAccount, context); /// perform the download @@ -506,15 +495,15 @@ private void saveDownloadedFile() { private void notifyDownloadStart(DownloadFileOperation download) { /// create status notification with a progress bar mLastPercent = 0; - mNotificationBuilder = NotificationUtils.newNotificationBuilder(activity, viewThemeUtils); + mNotificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils); mNotificationBuilder .setSmallIcon(R.drawable.notification_icon) - .setTicker(activity.getString(R.string.downloader_download_in_progress_ticker)) - .setContentTitle(activity.getString(R.string.downloader_download_in_progress_ticker)) + .setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) + .setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) .setOngoing(true) .setProgress(100, 0, download.getSize() < 0) .setContentText( - String.format(activity.getString(R.string.downloader_download_in_progress_content), 0, + String.format(context.getString(R.string.downloader_download_in_progress_content), 0, new File(download.getSavePath()).getName())); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { @@ -524,20 +513,20 @@ private void notifyDownloadStart(DownloadFileOperation download) { /// includes a pending intent in the notification showing the details view of the file Intent showDetailsIntent = null; if (PreviewImageFragment.canBePreviewed(download.getFile())) { - showDetailsIntent = new Intent(activity, PreviewImageActivity.class); + showDetailsIntent = new Intent(context, PreviewImageActivity.class); } else { - showDetailsIntent = new Intent(activity, FileDisplayActivity.class); + showDetailsIntent = new Intent(context, FileDisplayActivity.class); } showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, download.getFile()); showDetailsIntent.putExtra(FileActivity.EXTRA_USER, download.getUser()); showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - mNotificationBuilder.setContentIntent(PendingIntent.getActivity(activity, (int) System.currentTimeMillis(), + mNotificationBuilder.setContentIntent(PendingIntent.getActivity(context, (int) System.currentTimeMillis(), showDetailsIntent, PendingIntent.FLAG_IMMUTABLE)); if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); + mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); } if (mNotificationManager != null) { mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotificationBuilder.build()); @@ -555,11 +544,11 @@ public void onTransferProgress(long progressRate, long totalTransferredSoFar, if (percent != mLastPercent) { mNotificationBuilder.setProgress(100, percent, totalToTransfer < 0); String fileName = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1); - String text = String.format(activity.getString(R.string.downloader_download_in_progress_content), percent, fileName); + String text = String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName); mNotificationBuilder.setContentText(text); if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); + mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); } if (mNotificationManager != null) { @@ -581,7 +570,7 @@ public void onTransferProgress(long progressRate, long totalTransferredSoFar, private void notifyDownloadResult(DownloadFileOperation download, RemoteOperationResult downloadResult) { if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) activity.getSystemService(NOTIFICATION_SERVICE); + mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); } if (!downloadResult.isCancelled()) { @@ -600,8 +589,8 @@ private void notifyDownloadResult(DownloadFileOperation download, R.string.downloader_download_failed_credentials_error : tickerId; mNotificationBuilder - .setTicker(activity.getString(tickerId)) - .setContentTitle(activity.getString(tickerId)) + .setTicker(context.getString(tickerId)) + .setContentTitle(context.getString(tickerId)) .setAutoCancel(true) .setOngoing(false) .setProgress(0, 0, false); @@ -612,12 +601,12 @@ private void notifyDownloadResult(DownloadFileOperation download, } else { // TODO put something smart in showDetailsIntent Intent showDetailsIntent = new Intent(); - mNotificationBuilder.setContentIntent(PendingIntent.getActivity(activity, (int) System.currentTimeMillis(), + mNotificationBuilder.setContentIntent(PendingIntent.getActivity(context, (int) System.currentTimeMillis(), showDetailsIntent, PendingIntent.FLAG_IMMUTABLE)); } mNotificationBuilder.setContentText(ErrorMessageAdapter.getErrorCauseMessage(downloadResult, - download, activity.getResources())); + download, context.getResources())); if (mNotificationManager != null) { mNotificationManager.notify((new SecureRandom()).nextInt(), mNotificationBuilder.build()); @@ -634,7 +623,7 @@ private void notifyDownloadResult(DownloadFileOperation download, private void configureUpdateCredentialsNotification(User user) { // let the user update credentials with one click - Intent updateAccountCredentials = new Intent(activity, AuthenticatorActivity.class); + Intent updateAccountCredentials = new Intent(context, AuthenticatorActivity.class); updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()); updateAccountCredentials.putExtra( AuthenticatorActivity.EXTRA_ACTION, @@ -644,7 +633,7 @@ private void configureUpdateCredentialsNotification(User user) { updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND); mNotificationBuilder.setContentIntent( - PendingIntent.getActivity(activity, + PendingIntent.getActivity(context, (int) System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE) @@ -675,7 +664,7 @@ private void sendBroadcastDownloadFinished( if (unlinkedFromRemotePath != null) { end.putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath); } - end.setPackage(activity.getPackageName()); + end.setPackage(context.getPackageName()); localBroadcastManager.sendBroadcast(end); } @@ -692,7 +681,7 @@ private void sendBroadcastNewDownload(DownloadFileOperation download, added.putExtra(ACCOUNT_NAME, download.getUser().getAccountName()); added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath()); added.putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath); - added.setPackage(activity.getPackageName()); + added.setPackage(context.getPackageName()); localBroadcastManager.sendBroadcast(added); } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java index e993df4f66f4..80c4e2411a36 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -22,12 +22,13 @@ package com.owncloud.android.operations; import android.content.Context; +import android.content.Intent; import android.text.TextUtils; import com.nextcloud.client.account.User; -import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.NameCollisionPolicy; import com.owncloud.android.lib.common.OwnCloudClient; @@ -309,19 +310,29 @@ private void requestForUpload(OCFile file) { mTransferWasRequested = true; } + + /** + * Requests for a download to the FileDownloader service + * + * @param file OCFile object representing the file to download + */ private void requestForDownload(OCFile file) { - FileDownloadHelper.Companion.instance().downloadFile( - mUser, - file); + Intent i = new Intent(mContext, FileDownloader.class); + i.putExtra(FileDownloader.EXTRA_USER, mUser); + i.putExtra(FileDownloader.EXTRA_FILE, file); + new FileDownloader(i); mTransferWasRequested = true; } + public boolean transferWasRequested() { return mTransferWasRequested; } + public OCFile getLocalFile() { return mLocalFile; } + } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt index b85f3925c5e1..830fee88af4f 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt @@ -21,13 +21,13 @@ import android.content.Intent import android.os.Bundle import android.widget.Toast import com.nextcloud.client.account.User -import com.nextcloud.client.files.downloader.FileDownloadHelper import com.nextcloud.model.HTTPStatusCodes import com.nextcloud.utils.extensions.getParcelableArgument import com.owncloud.android.R import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.db.OCUpload +import com.owncloud.android.files.services.FileDownloader import com.owncloud.android.files.services.FileUploader import com.owncloud.android.files.services.NameCollisionPolicy import com.owncloud.android.lib.common.utils.Log_OC @@ -114,13 +114,12 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener Decision.KEEP_SERVER -> if (!shouldDeleteLocal()) { // Overwrite local file - file?.let { - FileDownloadHelper.instance().downloadFile( - getUser().orElseThrow { RuntimeException() }, - file, - conflictUploadId = conflictUploadId - ) - } + val intent = Intent(baseContext, FileDownloader::class.java) + intent.putExtra(FileDownloader.EXTRA_USER, getUser().orElseThrow { RuntimeException() }) + intent.putExtra(FileDownloader.EXTRA_FILE, file) + intent.putExtra(EXTRA_CONFLICT_UPLOAD_ID, conflictUploadId) + + FileDownloader(intent) } else { uploadsStorageManager!!.removeUpload(upload) } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index 151d177df8cb..27ae30f27f45 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -43,8 +43,6 @@ import com.google.android.material.snackbar.Snackbar; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; -import com.nextcloud.client.files.downloader.FileDownloadHelper; -import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.utils.EditorUtils; @@ -56,6 +54,8 @@ import com.owncloud.android.datamodel.ArbitraryDataProvider; import com.owncloud.android.datamodel.ArbitraryDataProviderImpl; import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.files.services.FileDownloader; +import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.lib.common.OwnCloudAccount; @@ -166,8 +166,9 @@ public abstract class FileActivity extends DrawerActivity private boolean mResumed; - protected FileDownloadWorker.FileDownloadProgressListener fileDownloadProgressListener; + protected FileDownloaderBinder mDownloaderBinder; protected FileUploaderBinder mUploaderBinder; + private ServiceConnection mDownloadServiceConnection; private ServiceConnection mUploadServiceConnection; @Inject @@ -205,7 +206,6 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mHandler = new Handler(); mFileOperationsHelper = new FileOperationsHelper(this, getUserAccountManager(), connectivityService, editorUtils); - User user = null; if (savedInstanceState != null) { mFile = BundleExtensionsKt.getParcelableArgument(savedInstanceState, FileActivity.EXTRA_FILE, OCFile.class); @@ -218,20 +218,24 @@ protected void onCreate(Bundle savedInstanceState) { viewThemeUtils.files.themeActionBar(this, actionBar, savedInstanceState.getString(KEY_ACTION_BAR_TITLE)); } } else { - user = IntentExtensionsKt.getParcelableArgument(getIntent(), FileActivity.EXTRA_USER, User.class); + User user = IntentExtensionsKt.getParcelableArgument(getIntent(), FileActivity.EXTRA_USER, User.class); mFile = IntentExtensionsKt.getParcelableArgument(getIntent(), FileActivity.EXTRA_FILE, OCFile.class); mFromNotification = getIntent().getBooleanExtra(FileActivity.EXTRA_FROM_NOTIFICATION, false); - if (user != null) { setUser(user); } } + mOperationsServiceConnection = new OperationsServiceConnection(); bindService(new Intent(this, OperationsService.class), mOperationsServiceConnection, Context.BIND_AUTO_CREATE); + mDownloadServiceConnection = newTransferenceServiceConnection(); + if (mDownloadServiceConnection != null) { + new FileDownloader(new Intent(this, FileDownloader.class)); + } mUploadServiceConnection = newTransferenceServiceConnection(); if (mUploadServiceConnection != null) { bindService(new Intent(this, FileUploader.class), mUploadServiceConnection, @@ -275,6 +279,10 @@ protected void onDestroy() { unbindService(mOperationsServiceConnection); mOperationsServiceBinder = null; } + if (mDownloadServiceConnection != null) { + unbindService(mDownloadServiceConnection); + mDownloadServiceConnection = null; + } if (mUploadServiceConnection != null) { unbindService(mUploadServiceConnection); mUploadServiceConnection = null; @@ -607,8 +615,8 @@ public void onServiceDisconnected(ComponentName component) { } @Override - public FileDownloadWorker.FileDownloadProgressListener getFileDownloadProgressListener() { - return fileDownloadProgressListener; + public FileDownloaderBinder getFileDownloaderBinder() { + return mDownloaderBinder; } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 0fbf73a091a3..1152562ae92d 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -37,25 +37,22 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; -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.WorkerState; -import com.nextcloud.model.WorkerStateLiveData; import com.nextcloud.utils.extensions.IntentExtensionsKt; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.VirtualFolderType; +import com.owncloud.android.files.services.FileDownloader; +import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.lib.common.operations.OnRemoteOperationListener; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.operations.DownloadType; import com.owncloud.android.operations.RemoveFileOperation; import com.owncloud.android.operations.SynchronizeFileOperation; import com.owncloud.android.ui.activity.FileActivity; @@ -102,8 +99,6 @@ public class PreviewImageActivity extends FileActivity implements private DownloadFinishReceiver mDownloadFinishReceiver; private UploadFinishReceiver mUploadFinishReceiver; private View mFullScreenAnchorView; - private boolean isDownloadWorkStarted = false; - @Inject AppPreferences preferences; @Inject LocalBroadcastManager localBroadcastManager; @@ -151,8 +146,6 @@ protected void onCreate(Bundle savedInstanceState) { } else { mRequestWaitingForBinder = false; } - - observeWorkerState(); } public void toggleActionBarVisibility(boolean hide) { @@ -306,25 +299,6 @@ private void onSynchronizeFileOperationFinish(RemoteOperationResult result) { } } - private void observeWorkerState() { - WorkerStateLiveData.Companion.instance().observe(this, state -> { - if (state instanceof WorkerState.Download) { - Log_OC.d(TAG, "Download worker started"); - isDownloadWorkStarted = true; - - if (mRequestWaitingForBinder) { - mRequestWaitingForBinder = false; - Log_OC.d(TAG, "Simulating reselection of current page after connection " + - "of download binder"); - onPageSelected(mViewPager.getCurrentItem()); - } - } else { - Log_OC.d(TAG, "Download worker stopped"); - isDownloadWorkStarted = false; - } - }); - } - @Override protected ServiceConnection newTransferenceServiceConnection() { return new PreviewImageServiceConnection(); @@ -335,7 +309,18 @@ private class PreviewImageServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { + if (component.equals(new ComponentName(PreviewImageActivity.this, + FileDownloader.class))) { + mDownloaderBinder = (FileDownloaderBinder) service; + if (mRequestWaitingForBinder) { + mRequestWaitingForBinder = false; + Log_OC.d(TAG, "Simulating reselection of current page after connection " + + "of download binder"); + onPageSelected(mViewPager.getCurrentItem()); + } + + } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service connected"); mUploaderBinder = (FileUploaderBinder) service; @@ -346,6 +331,10 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { if (component.equals(new ComponentName(PreviewImageActivity.this, + FileDownloader.class))) { + Log_OC.d(TAG, "Download service suddenly disconnected"); + mDownloaderBinder = null; + } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service suddenly disconnected"); mUploaderBinder = null; @@ -370,7 +359,7 @@ protected void onResume() { super.onResume(); mDownloadFinishReceiver = new DownloadFinishReceiver(); - IntentFilter downloadIntentFilter = new IntentFilter(FileDownloadWorker.Companion.getDownloadFinishMessage()); + IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.getDownloadFinishMessage()); localBroadcastManager.registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); mUploadFinishReceiver = new UploadFinishReceiver(); @@ -419,8 +408,19 @@ public void requestForDownload(OCFile file) { } public void requestForDownload(OCFile file, String downloadBehaviour) { - final User user = getUser().orElseThrow(RuntimeException::new); - FileDownloadHelper.Companion.instance().downloadFileIfNotStartedBefore(user, file); + if (mDownloaderBinder == null) { + Log_OC.d(TAG, "requestForDownload called without binder to download service"); + + } else if (!mDownloaderBinder.isDownloading(getUserAccountManager().getUser(), file)) { + final User user = getUser().orElseThrow(RuntimeException::new); + Intent i = new Intent(this, FileDownloader.class); + i.putExtra(FileDownloader.EXTRA_USER, user); + i.putExtra(FileDownloader.EXTRA_FILE, file); + if (downloadBehaviour != null) { + i.putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, downloadBehaviour); + } + new FileDownloader(i); + } } /** @@ -433,7 +433,7 @@ public void requestForDownload(OCFile file, String downloadBehaviour) { public void onPageSelected(int position) { mSavedPosition = position; mHasSavedPosition = true; - if (!isDownloadWorkStarted) { + if (mDownloaderBinder == null) { mRequestWaitingForBinder = true; } else { OCFile currentFile = mPreviewImagePagerAdapter.getFileAt(position); @@ -484,7 +484,7 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse } /** - * Class waiting for broadcast events from the {@link FileDownloadWorker} service. + * Class waiting for broadcast events from the {@link FileDownloader} service. * * Updates the UI when a download is started or finished, provided that it is relevant for the * folder displayed in the gallery. @@ -504,12 +504,12 @@ public void onReceive(Context context, Intent intent) { } private void previewNewImage(Intent intent) { - String accountName = intent.getStringExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME); - String downloadedRemotePath = intent.getStringExtra(FileDownloadWorker.EXTRA_REMOTE_PATH); + String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME); + String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH); String downloadBehaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); if (getAccount().name.equals(accountName) && downloadedRemotePath != null) { OCFile file = getStorageManager().getFileByPath(downloadedRemotePath); - boolean downloadWasFine = intent.getBooleanExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, false); + boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false); if (EditImageActivity.OPEN_IMAGE_EDITOR.equals(downloadBehaviour)) { startImageEditor(file); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index a1ef3e805734..2b685b8a8c59 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -53,7 +53,6 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; -import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.media.ExoplayerListener; import com.nextcloud.client.media.NextcloudExoPlayer; @@ -67,6 +66,7 @@ import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.ThumbnailsCacheManager; import com.owncloud.android.files.StreamMediaFileOperation; +import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; @@ -478,7 +478,12 @@ public void onFileActionChosen(final int itemId) { getView(), backgroundJobManager); } else if (itemId == R.id.action_download_file) { - FileDownloadHelper.Companion.instance().downloadFileIfNotStartedBefore(user, getFile()); + if (!containerActivity.getFileDownloaderBinder().isDownloading(user, getFile())) { + Intent i = new Intent(requireActivity(), FileDownloader.class); + i.putExtra(FileDownloader.EXTRA_USER, user); + i.putExtra(FileDownloader.EXTRA_FILE, getFile()); + new FileDownloader(i); + } } } From e33ef3b2a5e8c526a10d6f5678991185fef12173 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 12:55:52 +0100 Subject: [PATCH 093/189] Rebase master Signed-off-by: alperozturk --- .../com/nextcloud/client/di/AppComponent.java | 4 +- .../files/downloader/FilesDownloadHelper.kt | 63 +++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt diff --git a/app/src/main/java/com/nextcloud/client/di/AppComponent.java b/app/src/main/java/com/nextcloud/client/di/AppComponent.java index 47ec8d9e5881..4c677a313c6c 100644 --- a/app/src/main/java/com/nextcloud/client/di/AppComponent.java +++ b/app/src/main/java/com/nextcloud/client/di/AppComponent.java @@ -26,7 +26,7 @@ import com.nextcloud.client.appinfo.AppInfoModule; import com.nextcloud.client.database.DatabaseModule; import com.nextcloud.client.device.DeviceModule; -import com.nextcloud.client.files.downloader.FileDownloadHelper; +import com.nextcloud.client.files.downloader.FilesDownloadHelper; import com.nextcloud.client.integrations.IntegrationsModule; import com.nextcloud.client.jobs.JobsModule; import com.nextcloud.client.network.NetworkModule; @@ -72,7 +72,7 @@ public interface AppComponent { void inject(FilesUploadHelper filesUploadHelper); - void inject(FileDownloadHelper fileDownloadHelper); + void inject(FilesDownloadHelper filesDownloadHelper); void inject(ProgressIndicator progressIndicator); diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt new file mode 100644 index 000000000000..b5e316a28871 --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt @@ -0,0 +1,63 @@ +/* + * 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 . + */ + +package com.nextcloud.client.files.downloader + +import com.nextcloud.client.account.User +import com.nextcloud.client.jobs.BackgroundJobManager +import com.owncloud.android.MainApp +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.datamodel.UploadsStorageManager +import com.owncloud.android.operations.DownloadType +import javax.inject.Inject + +class FilesDownloadHelper { + + @Inject + lateinit var backgroundJobManager: BackgroundJobManager + + @Inject + lateinit var uploadsStorageManager: UploadsStorageManager + + init { + MainApp.getAppComponent().inject(this) + } + + fun downloadFile( + user: User, + ocFile: OCFile, + behaviour: String, + downloadType: DownloadType, + activityName: String, + packageName: String, + conflictUploadId: Long + ) { + backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + behaviour, + downloadType, + activityName, + packageName, + conflictUploadId + ) + } +} From dcbf89c3d276b8299564975a969f3ba02480b67c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 11:33:05 +0100 Subject: [PATCH 094/189] Implement FilesDownloadWorker Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 489 +++++++++++++++++- .../files/services/FileDownloader.java | 9 +- 2 files changed, 489 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index 52119e015c64..90b81bd618b7 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -21,24 +21,71 @@ package com.nextcloud.client.files.downloader +import android.accounts.Account +import android.accounts.AccountManager +import android.accounts.OnAccountsUpdateListener +import android.app.Notification +import android.app.NotificationManager +import android.app.PendingIntent import android.content.Context +import android.content.Intent +import android.graphics.BitmapFactory +import android.os.Binder +import android.os.Build +import android.os.Handler +import android.os.IBinder +import android.os.Looper +import android.os.Message +import android.util.Pair +import androidx.core.app.NotificationCompat import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters +import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.java.util.Optional +import com.owncloud.android.R +import com.owncloud.android.authentication.AuthenticatorActivity +import com.owncloud.android.datamodel.FileDataStorageManager +import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager +import com.owncloud.android.files.services.FileDownloader +import com.owncloud.android.files.services.IndexedForest +import com.owncloud.android.lib.common.OwnCloudClient +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory +import com.owncloud.android.lib.common.network.OnDatatransferProgressListener +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode +import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.resources.files.FileUtils +import com.owncloud.android.operations.DownloadFileOperation +import com.owncloud.android.operations.DownloadType +import com.owncloud.android.ui.activity.FileActivity +import com.owncloud.android.ui.activity.FileDisplayActivity +import com.owncloud.android.ui.dialog.SendShareDialog +import com.owncloud.android.ui.fragment.OCFileListFragment +import com.owncloud.android.ui.notifications.NotificationUtils +import com.owncloud.android.ui.preview.PreviewImageActivity +import com.owncloud.android.ui.preview.PreviewImageFragment +import com.owncloud.android.utils.ErrorMessageAdapter +import com.owncloud.android.utils.MimeTypeUtil import com.owncloud.android.utils.theme.ViewThemeUtils +import java.io.File +import java.security.SecureRandom +import java.util.AbstractList +import java.util.Vector class FilesDownloadWorker( private val viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, private val uploadsStorageManager: UploadsStorageManager, private var localBroadcastManager: LocalBroadcastManager, - context: Context, + private val context: Context, params: WorkerParameters, -) : Worker(context, params) { +) : Worker(context, params), OnAccountsUpdateListener, OnDatatransferProgressListener { companion object { + private val TAG = FilesDownloadWorker::class.java.simpleName const val USER = "USER" const val FILE = "FILE" const val BEHAVIOUR = "BEHAVIOUR" @@ -48,11 +95,449 @@ class FilesDownloadWorker( const val CONFLICT_UPLOAD_ID = "CONFLICT_UPLOAD_ID" } + private var notification: Notification? = null + private var currentDownload: DownloadFileOperation? = null + private var conflictUploadId: Long? = null + private var lastPercent = 0 + private var notificationBuilder: NotificationCompat.Builder? = null + private var notificationManager: NotificationManager? = null + private val pendingDownloads = IndexedForest() + private var downloadBinder: IBinder? = null + private var currentUser = Optional.empty() + private val workerHandler: WorkerHandler? = null + private var startedDownload = false + private var storageManager: FileDataStorageManager? = null + private var downloadClient: OwnCloudClient? = null + override fun doWork(): Result { return try { + conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long + val user = inputData.keyValueMap[USER] as User + val file = inputData.keyValueMap[FILE] as OCFile + val downloadType = inputData.keyValueMap[DOWNLOAD_TYPE] as DownloadType + val behaviour = inputData.keyValueMap[BEHAVIOUR] as String + val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String + val packageName = inputData.keyValueMap[PACKAGE_NAME] as String + downloadBinder = FileDownloaderBinder() + + showDownloadingFilesNotification() + addAccountUpdateListener() + download(user, file, behaviour, downloadType, activityName, packageName) + Result.success() } catch (t: Throwable) { Result.failure() } } + + private fun download( + user: User, + file: OCFile, + behaviour: String, + downloadType: DownloadType, + activityName: String, + packageName: String, + ) { + val requestedDownloads: AbstractList = Vector() + try { + val newDownload = DownloadFileOperation( + user, + file, + behaviour, + activityName, + packageName, + context, + downloadType + ) + newDownload.addDatatransferProgressListener(this) + newDownload.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder?) + val putResult: Pair = pendingDownloads.putIfAbsent( + user.accountName, + file.remotePath, + newDownload + ) + + val downloadKey = putResult.first + requestedDownloads.add(downloadKey) + sendBroadcastNewDownload(newDownload, putResult.second) + } catch (e: IllegalArgumentException) { + Log_OC.e(TAG, "Not enough information provided in intent: " + e.message) + } + + if (requestedDownloads.size > 0) { + val msg: Message? = workerHandler?.obtainMessage() + // msg.arg1 = startId; + msg?.obj = requestedDownloads + + msg?.let { + workerHandler?.sendMessage(msg) + } + } + } + + private fun downloadFile(downloadKey: String) { + startedDownload = true + currentDownload = pendingDownloads.get(downloadKey) + if (currentDownload != null) { + if (accountManager.exists(currentDownload?.user?.toPlatformAccount())) { + notifyDownloadStart(currentDownload!!) + var downloadResult: RemoteOperationResult<*>? = null + try { + /// prepare client object to send the request to the ownCloud server + val currentDownloadAccount: Account? = currentDownload?.user?.toPlatformAccount() + val currentDownloadUser = accountManager.getUser(currentDownloadAccount?.name) + if (currentUser != currentDownloadUser) { + currentUser = currentDownloadUser + storageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) + } // else, reuse storage manager from previous operation + + val ocAccount = currentDownloadUser.get().toOwnCloudAccount() + downloadClient = + OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, context) + + downloadResult = currentDownload!!.execute(downloadClient) + if (downloadResult?.isSuccess == true && currentDownload?.downloadType === DownloadType.DOWNLOAD) { + saveDownloadedFile() + } + } catch (e: Exception) { + Log_OC.e(TAG, "Error downloading", e) + downloadResult = RemoteOperationResult(e) + } finally { + val removeResult: Pair = pendingDownloads.removePayload( + currentDownload?.user?.accountName, currentDownload?.remotePath + ) + + if (downloadResult == null) { + downloadResult = RemoteOperationResult(RuntimeException("Error downloading…")) + } + + currentDownload?.let { + notifyDownloadResult(it, downloadResult) + sendBroadcastDownloadFinished(it, downloadResult, removeResult.second) + } + } + } else { + cancelPendingDownloads(currentDownload?.user?.accountName) + } + } + } + + private fun saveDownloadedFile() { + var file: OCFile? = currentDownload?.file?.fileId?.let { storageManager?.getFileById(it) } + if (file == null) { + // try to get file via path, needed for overwriting existing files on conflict dialog + file = storageManager?.getFileByDecryptedRemotePath(currentDownload?.file?.remotePath) + } + if (file == null) { + Log_OC.e(this, "Could not save " + currentDownload?.file?.remotePath) + return + } + val syncDate = System.currentTimeMillis() + file.lastSyncDateForProperties = syncDate + file.lastSyncDateForData = syncDate + file.isUpdateThumbnailNeeded = true + file.modificationTimestamp = currentDownload?.modificationTimestamp ?: 0L + file.modificationTimestampAtLastSyncForData = currentDownload?.modificationTimestamp ?: 0L + file.etag = currentDownload?.etag + file.mimeType = currentDownload?.mimeType + file.storagePath = currentDownload?.savePath + file.fileLength = File(currentDownload?.getSavePath()).length() + file.remoteId = currentDownload?.file?.remoteId + storageManager?.saveFile(file) + + if (MimeTypeUtil.isMedia(currentDownload?.mimeType)) { + FileDataStorageManager.triggerMediaScan(file.storagePath, file) + } + + storageManager?.saveConflict(file, null) + } + + private fun sendBroadcastDownloadFinished( + download: DownloadFileOperation, + downloadResult: RemoteOperationResult<*>, + unlinkedFromRemotePath: String? + ) { + val end = Intent(FileDownloader.getDownloadFinishMessage()) + end.putExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) + end.putExtra(FileDownloader.ACCOUNT_NAME, download.user.accountName) + end.putExtra(FileDownloader.EXTRA_REMOTE_PATH, download.remotePath) + end.putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) + end.putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) + end.putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) + if (unlinkedFromRemotePath != null) { + end.putExtra(FileDownloader.EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) + } + end.setPackage(context.packageName) + localBroadcastManager.sendBroadcast(end) + } + + private fun notifyDownloadResult( + download: DownloadFileOperation, + downloadResult: RemoteOperationResult<*> + ) { + if (notificationManager == null) { + notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + } + + if (!downloadResult.isCancelled) { + if (downloadResult.isSuccess) { + if (conflictUploadId!! > 0) { + uploadsStorageManager.removeUpload(conflictUploadId!!) + } + // Dont show notification except an error has occured. + return + } + var tickerId = + if (downloadResult.isSuccess) R.string.downloader_download_succeeded_ticker else R.string.downloader_download_failed_ticker + val needsToUpdateCredentials = ResultCode.UNAUTHORIZED == downloadResult.code + tickerId = if (needsToUpdateCredentials) R.string.downloader_download_failed_credentials_error else tickerId + + notificationBuilder + ?.setTicker(context.getString(tickerId)) + ?.setContentTitle(context.getString(tickerId)) + ?.setAutoCancel(true) + ?.setOngoing(false) + ?.setProgress(0, 0, false) + + if (needsToUpdateCredentials) { + configureUpdateCredentialsNotification(download.user) + } else { + // TODO put something smart in showDetailsIntent + val showDetailsIntent = Intent() + notificationBuilder?.setContentIntent( + PendingIntent.getActivity( + context, System.currentTimeMillis().toInt(), + showDetailsIntent, PendingIntent.FLAG_IMMUTABLE + ) + ) + } + + notificationBuilder?.setContentText( + ErrorMessageAdapter.getErrorCauseMessage( + downloadResult, + download, context.resources + ) + ) + + if (notificationManager != null) { + notificationManager?.notify(SecureRandom().nextInt(), notificationBuilder?.build()) + if (downloadResult.isSuccess) { + NotificationUtils.cancelWithDelay( + notificationManager, + R.string.downloader_download_succeeded_ticker, 2000 + ) + } + } + } + } + + private fun configureUpdateCredentialsNotification(user: User) { + val updateAccountCredentials = Intent(context, AuthenticatorActivity::class.java) + updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) + updateAccountCredentials.putExtra( + AuthenticatorActivity.EXTRA_ACTION, + AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN + ) + updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND) + notificationBuilder?.setContentIntent( + PendingIntent.getActivity( + context, System.currentTimeMillis().toInt(), + updateAccountCredentials, + PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE + ) + ) + } + + private fun notifyDownloadStart(download: DownloadFileOperation) { + lastPercent = 0 + notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) + .setSmallIcon(R.drawable.notification_icon) + .setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) + .setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) + .setOngoing(true) + .setProgress(100, 0, download.size < 0) + .setContentText( + String.format( + context.getString(R.string.downloader_download_in_progress_content), 0, + File(download.savePath).name + ) + ) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationBuilder?.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + } + + /// includes a pending intent in the notification showing the details view of the file + var showDetailsIntent: Intent? = null + showDetailsIntent = if (PreviewImageFragment.canBePreviewed(download.file)) { + Intent(context, PreviewImageActivity::class.java) + } else { + Intent(context, FileDisplayActivity::class.java) + } + showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, download.file) + showDetailsIntent.putExtra(FileActivity.EXTRA_USER, download.user) + showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + notificationBuilder?.setContentIntent( + PendingIntent.getActivity( + context, System.currentTimeMillis().toInt(), + showDetailsIntent, PendingIntent.FLAG_IMMUTABLE + ) + ) + + if (notificationManager == null) { + notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + } + if (notificationManager != null) { + notificationManager?.notify(R.string.downloader_download_in_progress_ticker, notificationBuilder?.build()) + } + } + + private fun showDownloadingFilesNotification() { + val builder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) + .setContentTitle(context.resources.getString(R.string.app_name)) + .setContentText(context.resources.getString(R.string.foreground_service_download)) + .setSmallIcon(R.drawable.notification_icon) + .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) + + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + builder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + } + + notification = builder.build() + } + + private fun addAccountUpdateListener() { + val am = AccountManager.get(context) + am.addOnAccountsUpdatedListener(this, null, false) + } + + private fun cancelPendingDownloads(accountName: String?) { + pendingDownloads.remove(accountName) + } + + private fun sendBroadcastNewDownload( + download: DownloadFileOperation, + linkedToRemotePath: String + ) { + val added = Intent(FileDownloader.getDownloadAddedMessage()) + added.putExtra(FileDownloader.ACCOUNT_NAME, download.user.accountName) + added.putExtra(FileDownloader.EXTRA_REMOTE_PATH, download.remotePath) + added.putExtra(FileDownloader.EXTRA_LINKED_TO_PATH, linkedToRemotePath) + added.setPackage(context.packageName) + localBroadcastManager.sendBroadcast(added) + } + + override fun onAccountsUpdated(accounts: Array?) { + if (currentDownload != null && !accountManager.exists(currentDownload?.user?.toPlatformAccount())) { + currentDownload?.cancel() + } + } + + override fun onTransferProgress( + progressRate: Long, + totalTransferredSoFar: Long, + totalToTransfer: Long, + filePath: String + ) { + val percent: Int = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt() + if (percent != lastPercent) { + notificationBuilder?.setProgress(100, percent, totalToTransfer < 0) + val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) + val text = + String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) + notificationBuilder?.setContentText(text) + + if (notificationManager == null) { + notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + } + if (notificationManager != null) { + notificationManager?.notify( + R.string.downloader_download_in_progress_ticker, + notificationBuilder?.build() + ) + } + } + lastPercent = percent + } + + inner class FileDownloaderBinder : Binder(), OnDatatransferProgressListener { + /** + * Map of listeners that will be reported about progress of downloads from a + * [FileDownloaderBinder] + * instance. + */ + private val mBoundListeners: MutableMap = HashMap() + + /** + * Cancels a pending or current download of a remote file. + * + * @param account ownCloud account where the remote file is stored. + * @param file A file in the queue of pending downloads + */ + fun cancel(account: Account, file: OCFile) { + val removeResult: Pair = + pendingDownloads.remove(account.name, file.remotePath) + val download = removeResult.first + if (download != null) { + download.cancel() + } else { + if (currentDownload != null && currentUser?.isPresent == true && + currentDownload?.remotePath?.startsWith(file.remotePath) == true && account.name == currentUser.get()?.accountName + ) { + currentDownload?.cancel() + } + } + } + + /** + * Cancels all the downloads for an account + */ + fun cancel(accountName: String?) { + if (currentDownload != null && currentDownload?.user?.nameEquals(accountName) == true) { + currentDownload?.cancel() + } + + cancelPendingDownloads(accountName) + } + + fun isDownloading(user: User?, file: OCFile?): Boolean { + return user != null && file != null && pendingDownloads.contains(user.accountName, file.remotePath) + } + + override fun onTransferProgress( + progressRate: Long, totalTransferredSoFar: Long, + totalToTransfer: Long, fileName: String + ) { + val boundListener = mBoundListeners[currentDownload?.file?.fileId] + boundListener?.onTransferProgress( + progressRate, totalTransferredSoFar, + totalToTransfer, fileName + ) + } + } + + private class WorkerHandler(looper: Looper, private val worker: FilesDownloadWorker) : Handler(looper) { + override fun handleMessage(msg: Message) { + val requestedDownloads = msg.obj as AbstractList + + if (msg.obj != null) { + val it: Iterator = requestedDownloads.iterator() + while (it.hasNext()) { + val next = it.next() + worker.downloadFile(next) + } + } + + worker.startedDownload = false + + Handler(Looper.getMainLooper()).postDelayed({ + if (!worker.startedDownload) { + worker.notificationManager?.cancel(R.string.downloader_download_in_progress_ticker) + } + Log_OC.d(TAG, "Stopping after command with id " + msg.arg1) + }, 2000) + } + } } diff --git a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java index a528d479ffe1..6a88b168f4fd 100644 --- a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java +++ b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java @@ -247,7 +247,7 @@ public void onAccountsUpdated(Account[] accounts) { *

* It provides by itself the available operations. */ - public class FileDownloaderBinder extends Binder implements OnDatatransferProgressListener { + public class FileDownloaderBinder2 extends Binder implements OnDatatransferProgressListener { /** * Map of listeners that will be reported about progress of downloads from a @@ -390,12 +390,7 @@ public void handleMessage(Message msg) { } - /** - * Core download method: requests a file to download and stores it. - * - * @param downloadKey Key to access the download to perform, contained in mPendingDownloads - */ - private void downloadFile(String downloadKey) { + void downloadFile(String downloadKey) { mStartedDownload = true; mCurrentDownload = mPendingDownloads.get(downloadKey); From b8042587900054d678f100b54da9bfc1209fe2c0 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 11:37:42 +0100 Subject: [PATCH 095/189] Implement FilesDownloadWorker Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 33 +++++++++++++------ .../files/services/FileDownloader.java | 6 ++-- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index 90b81bd618b7..791e03b31cb0 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -49,7 +49,6 @@ import com.owncloud.android.authentication.AuthenticatorActivity import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager -import com.owncloud.android.files.services.FileDownloader import com.owncloud.android.files.services.IndexedForest import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.OwnCloudClientManagerFactory @@ -93,6 +92,12 @@ class FilesDownloadWorker( const val ACTIVITY_NAME = "ACTIVITY_NAME" const val PACKAGE_NAME = "PACKAGE_NAME" const val CONFLICT_UPLOAD_ID = "CONFLICT_UPLOAD_ID" + const val EXTRA_USER = "USER" + const val EXTRA_FILE = "FILE" + const val EXTRA_DOWNLOAD_RESULT = "RESULT" + const val EXTRA_REMOTE_PATH = "REMOTE_PATH" + const val EXTRA_LINKED_TO_PATH = "LINKED_TO" + const val ACCOUNT_NAME = "ACCOUNT_NAME" } private var notification: Notification? = null @@ -257,15 +262,15 @@ class FilesDownloadWorker( downloadResult: RemoteOperationResult<*>, unlinkedFromRemotePath: String? ) { - val end = Intent(FileDownloader.getDownloadFinishMessage()) - end.putExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) - end.putExtra(FileDownloader.ACCOUNT_NAME, download.user.accountName) - end.putExtra(FileDownloader.EXTRA_REMOTE_PATH, download.remotePath) + val end = Intent(getDownloadFinishMessage()) + end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) + end.putExtra(ACCOUNT_NAME, download.user.accountName) + end.putExtra(EXTRA_REMOTE_PATH, download.remotePath) end.putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) end.putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) end.putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) if (unlinkedFromRemotePath != null) { - end.putExtra(FileDownloader.EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) + end.putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) } end.setPackage(context.packageName) localBroadcastManager.sendBroadcast(end) @@ -417,14 +422,22 @@ class FilesDownloadWorker( pendingDownloads.remove(accountName) } + private fun getDownloadAddedMessage(): String { + return FilesDownloadWorker::class.java.name + "DOWNLOAD_ADDED" + } + + private fun getDownloadFinishMessage(): String { + return FilesDownloadWorker::class.java.name + "DOWNLOAD_FINISH" + } + private fun sendBroadcastNewDownload( download: DownloadFileOperation, linkedToRemotePath: String ) { - val added = Intent(FileDownloader.getDownloadAddedMessage()) - added.putExtra(FileDownloader.ACCOUNT_NAME, download.user.accountName) - added.putExtra(FileDownloader.EXTRA_REMOTE_PATH, download.remotePath) - added.putExtra(FileDownloader.EXTRA_LINKED_TO_PATH, linkedToRemotePath) + val added = Intent(getDownloadAddedMessage()) + added.putExtra(ACCOUNT_NAME, download.user.accountName) + added.putExtra(EXTRA_REMOTE_PATH, download.remotePath) + added.putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath) added.setPackage(context.packageName) localBroadcastManager.sendBroadcast(added) } diff --git a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java index 6a88b168f4fd..b537db5fbf9d 100644 --- a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java +++ b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java @@ -97,11 +97,11 @@ public class FileDownloader implements OnDatatransferProgressListener, OnAccount private final Context context = MainApp.getAppContext(); private final Intent intent; - public static final String EXTRA_USER = "USER"; - public static final String EXTRA_FILE = "FILE"; - private static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED"; private static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH"; + + public static final String EXTRA_USER = "USER"; + public static final String EXTRA_FILE = "FILE"; public static final String EXTRA_DOWNLOAD_RESULT = "RESULT"; public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; public static final String EXTRA_LINKED_TO_PATH = "LINKED_TO"; From 0fd76576b2c02713923c9b88e2d4ad9a3b54b34a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 11:45:26 +0100 Subject: [PATCH 096/189] Refactor FilesDownloadWorker Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 104 ++++++++++-------- 1 file changed, 59 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index 791e03b31cb0..03e114612504 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -50,6 +50,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.files.services.IndexedForest +import com.owncloud.android.lib.common.OwnCloudAccount import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.OwnCloudClientManagerFactory import com.owncloud.android.lib.common.network.OnDatatransferProgressListener @@ -123,11 +124,12 @@ class FilesDownloadWorker( val behaviour = inputData.keyValueMap[BEHAVIOUR] as String val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String val packageName = inputData.keyValueMap[PACKAGE_NAME] as String + downloadBinder = FileDownloaderBinder() showDownloadingFilesNotification() addAccountUpdateListener() - download(user, file, behaviour, downloadType, activityName, packageName) + requestDownloads(user, file, behaviour, downloadType, activityName, packageName) Result.success() } catch (t: Throwable) { @@ -135,7 +137,7 @@ class FilesDownloadWorker( } } - private fun download( + private fun requestDownloads( user: User, file: OCFile, behaviour: String, @@ -145,7 +147,7 @@ class FilesDownloadWorker( ) { val requestedDownloads: AbstractList = Vector() try { - val newDownload = DownloadFileOperation( + val operation = DownloadFileOperation( user, file, behaviour, @@ -154,17 +156,17 @@ class FilesDownloadWorker( context, downloadType ) - newDownload.addDatatransferProgressListener(this) - newDownload.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder?) + operation.addDatatransferProgressListener(this) + operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder?) val putResult: Pair = pendingDownloads.putIfAbsent( user.accountName, file.remotePath, - newDownload + operation ) val downloadKey = putResult.first requestedDownloads.add(downloadKey) - sendBroadcastNewDownload(newDownload, putResult.second) + sendBroadcastNewDownload(operation, putResult.second) } catch (e: IllegalArgumentException) { Log_OC.e(TAG, "Not enough information provided in intent: " + e.message) } @@ -183,47 +185,59 @@ class FilesDownloadWorker( private fun downloadFile(downloadKey: String) { startedDownload = true currentDownload = pendingDownloads.get(downloadKey) - if (currentDownload != null) { - if (accountManager.exists(currentDownload?.user?.toPlatformAccount())) { - notifyDownloadStart(currentDownload!!) - var downloadResult: RemoteOperationResult<*>? = null - try { - /// prepare client object to send the request to the ownCloud server - val currentDownloadAccount: Account? = currentDownload?.user?.toPlatformAccount() - val currentDownloadUser = accountManager.getUser(currentDownloadAccount?.name) - if (currentUser != currentDownloadUser) { - currentUser = currentDownloadUser - storageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) - } // else, reuse storage manager from previous operation - - val ocAccount = currentDownloadUser.get().toOwnCloudAccount() - downloadClient = - OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, context) - - downloadResult = currentDownload!!.execute(downloadClient) - if (downloadResult?.isSuccess == true && currentDownload?.downloadType === DownloadType.DOWNLOAD) { - saveDownloadedFile() - } - } catch (e: Exception) { - Log_OC.e(TAG, "Error downloading", e) - downloadResult = RemoteOperationResult(e) - } finally { - val removeResult: Pair = pendingDownloads.removePayload( - currentDownload?.user?.accountName, currentDownload?.remotePath - ) - if (downloadResult == null) { - downloadResult = RemoteOperationResult(RuntimeException("Error downloading…")) - } + if (currentDownload == null) { + return + } - currentDownload?.let { - notifyDownloadResult(it, downloadResult) - sendBroadcastDownloadFinished(it, downloadResult, removeResult.second) - } - } - } else { - cancelPendingDownloads(currentDownload?.user?.accountName) + val isAccountExist = accountManager.exists(currentDownload?.user?.toPlatformAccount()) + if (!isAccountExist) { + cancelPendingDownloads(currentDownload?.user?.accountName) + return + } + + notifyDownloadStart(currentDownload!!) + var downloadResult: RemoteOperationResult<*>? = null + try { + val ocAccount = getOCAccountForDownload() + downloadClient = + OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, context) + + downloadResult = currentDownload?.execute(downloadClient) + if (downloadResult?.isSuccess == true && currentDownload?.downloadType === DownloadType.DOWNLOAD) { + saveDownloadedFile() } + } catch (e: Exception) { + Log_OC.e(TAG, "Error downloading", e) + downloadResult = RemoteOperationResult(e) + } finally { + cleanupDownloadProcess(downloadResult) + } + } + + private fun getOCAccountForDownload(): OwnCloudAccount { + val currentDownloadAccount = currentDownload?.user?.toPlatformAccount() + val currentDownloadUser = accountManager.getUser(currentDownloadAccount?.name) + if (currentUser != currentDownloadUser) { + currentUser = currentDownloadUser + storageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) + } + return currentDownloadUser.get().toOwnCloudAccount() + } + + private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { + var downloadResult = result + val removeResult: Pair = pendingDownloads.removePayload( + currentDownload?.user?.accountName, currentDownload?.remotePath + ) + + if (downloadResult == null) { + downloadResult = RemoteOperationResult(RuntimeException("Error downloading…")) + } + + currentDownload?.let { + notifyDownloadResult(it, downloadResult) + sendBroadcastDownloadFinished(it, downloadResult, removeResult.second) } } From f67b3a9f8353fb285629633d6d6a05bb87e102a0 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 12:56:01 +0100 Subject: [PATCH 097/189] Rebase master Signed-off-by: alperozturk --- .../android/files/FileMenuFilterIT.kt | 8 +- .../java/com/nextcloud/test/TestActivity.kt | 4 +- .../files/downloader/FilesDownloadHelper.kt | 4 +- .../files/downloader/FilesDownloadWorker.kt | 33 +- .../client/jobs/BackgroundJobManager.kt | 4 +- .../client/jobs/BackgroundJobManagerImpl.kt | 5 +- .../nextcloud/client/jobs/FilesExportWork.kt | 20 +- .../android/files/FileMenuFilter.java | 17 +- .../files/services/FileDownloader.java | 686 ------------------ .../operations/SynchronizeFileOperation.java | 17 +- .../SynchronizeFolderOperation.java | 26 +- .../providers/DocumentsStorageProvider.java | 2 +- .../android/services/SyncFolderHandler.java | 16 +- .../android/ui/activity/ComponentsGetter.java | 8 +- .../ui/activity/ConflictsResolveActivity.kt | 19 +- .../android/ui/activity/FileActivity.java | 16 +- .../ui/activity/FileDisplayActivity.java | 74 +- .../ui/activity/ManageAccountsActivity.java | 50 +- .../ui/fragment/FileDetailFragment.java | 23 +- .../ui/helpers/FileOperationsHelper.java | 9 +- .../ui/preview/PreviewImageActivity.java | 28 +- .../ui/preview/PreviewMediaFragment.java | 7 +- 22 files changed, 211 insertions(+), 865 deletions(-) delete mode 100644 app/src/main/java/com/owncloud/android/files/services/FileDownloader.java diff --git a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt index 9c19ce243f66..e031d92ccafe 100644 --- a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt @@ -23,7 +23,7 @@ package com.owncloud.android.files import androidx.test.core.app.launchActivity import androidx.test.ext.junit.runners.AndroidJUnit4 import com.nextcloud.client.account.User -import com.nextcloud.client.files.downloader.FileDownloadWorker +import com.nextcloud.client.files.downloader.FilesDownloadWorker import com.nextcloud.test.TestActivity import com.nextcloud.utils.EditorUtils import com.owncloud.android.AbstractIT @@ -62,7 +62,7 @@ class FileMenuFilterIT : AbstractIT() { private lateinit var mockFileUploaderBinder: FileUploader.FileUploaderBinder @MockK - private lateinit var mockFileDownloadProgressListener: FileDownloadWorker.FileDownloadProgressListener + private lateinit var mockFileDownloaderBinder: FilesDownloadWorker.FileDownloaderBinder @MockK private lateinit var mockOperationsServiceBinder: OperationsService.OperationsServiceBinder @@ -77,8 +77,8 @@ class FileMenuFilterIT : AbstractIT() { MockKAnnotations.init(this) every { mockFileUploaderBinder.isUploading(any(), any()) } returns false every { mockComponentsGetter.fileUploaderBinder } returns mockFileUploaderBinder - every { mockFileDownloadProgressListener.isDownloading(any(), any()) } returns false - every { mockComponentsGetter.fileDownloadProgressListener } returns mockFileDownloadProgressListener + every { mockFileDownloaderBinder.isDownloading(any(), any()) } returns false + every { mockComponentsGetter.fileDownloaderBinder } returns mockFileDownloaderBinder every { mockOperationsServiceBinder.isSynchronizing(any(), any()) } returns false every { mockComponentsGetter.operationsServiceBinder } returns mockOperationsServiceBinder every { mockStorageManager.getFileById(any()) } returns OCFile("/") diff --git a/app/src/debug/java/com/nextcloud/test/TestActivity.kt b/app/src/debug/java/com/nextcloud/test/TestActivity.kt index 23297a32851c..90c4ecc19a82 100644 --- a/app/src/debug/java/com/nextcloud/test/TestActivity.kt +++ b/app/src/debug/java/com/nextcloud/test/TestActivity.kt @@ -25,7 +25,7 @@ import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment import androidx.swiperefreshlayout.widget.SwipeRefreshLayout -import com.nextcloud.client.files.downloader.FileDownloadWorker +import com.nextcloud.client.files.downloader.FilesDownloadWorker import com.nextcloud.client.network.Connectivity import com.nextcloud.client.network.ConnectivityService import com.nextcloud.utils.EditorUtils @@ -130,7 +130,7 @@ class TestActivity : return null } - override fun getFileDownloadProgressListener(): FileDownloadWorker.FileDownloadProgressListener? { + override fun getFileDownloaderBinder(): FilesDownloadWorker.FileDownloaderBinder? { return null } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt index b5e316a28871..71f833c07bdc 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt @@ -45,10 +45,10 @@ class FilesDownloadHelper { user: User, ocFile: OCFile, behaviour: String, - downloadType: DownloadType, + downloadType: DownloadType?, activityName: String, packageName: String, - conflictUploadId: Long + conflictUploadId: Long? ) { backgroundJobManager.startFilesDownloadJob( user, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index 03e114612504..dfdf51781a96 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -99,6 +99,14 @@ class FilesDownloadWorker( const val EXTRA_REMOTE_PATH = "REMOTE_PATH" const val EXTRA_LINKED_TO_PATH = "LINKED_TO" const val ACCOUNT_NAME = "ACCOUNT_NAME" + + fun getDownloadAddedMessage(): String { + return FilesDownloadWorker::class.java.name + "DOWNLOAD_ADDED" + } + + fun getDownloadFinishMessage(): String { + return FilesDownloadWorker::class.java.name + "DOWNLOAD_FINISH" + } } private var notification: Notification? = null @@ -436,14 +444,6 @@ class FilesDownloadWorker( pendingDownloads.remove(accountName) } - private fun getDownloadAddedMessage(): String { - return FilesDownloadWorker::class.java.name + "DOWNLOAD_ADDED" - } - - private fun getDownloadFinishMessage(): String { - return FilesDownloadWorker::class.java.name + "DOWNLOAD_FINISH" - } - private fun sendBroadcastNewDownload( download: DownloadFileOperation, linkedToRemotePath: String @@ -533,6 +533,23 @@ class FilesDownloadWorker( return user != null && file != null && pendingDownloads.contains(user.accountName, file.remotePath) } + fun addDatatransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { + if (file == null || listener == null) { + return + } + mBoundListeners[file.fileId] = listener + } + + fun removeDatatransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { + if (file == null || listener == null) { + return + } + val fileId = file.fileId + if (mBoundListeners[fileId] === listener) { + mBoundListeners.remove(fileId) + } + } + override fun onTransferProgress( progressRate: Long, totalTransferredSoFar: Long, totalToTransfer: Long, fileName: String diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index fbcc04922e17..30f7ab3c7595 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -149,10 +149,10 @@ interface BackgroundJobManager { user: User, ocFile: OCFile, behaviour: String, - downloadType: DownloadType, + downloadType: DownloadType?, activityName: String, packageName: String, - conflictUploadId: Long + conflictUploadId: Long? ) fun startPdfGenerateAndUploadWork(user: User, uploadFolder: String, imagePaths: List, pdfPath: String) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index d291189269de..943e9c6d0fc3 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -42,7 +42,6 @@ import com.nextcloud.client.files.downloader.FilesDownloadWorker import com.nextcloud.client.preferences.AppPreferences import com.owncloud.android.datamodel.OCFile import com.owncloud.android.operations.DownloadType -import java.io.File import java.util.Date import java.util.UUID import java.util.concurrent.TimeUnit @@ -513,10 +512,10 @@ internal class BackgroundJobManagerImpl( user: User, ocFile: OCFile, behaviour: String, - downloadType: DownloadType, + downloadType: DownloadType?, activityName: String, packageName: String, - conflictUploadId: Long + conflictUploadId: Long? ) { val data = workDataOf( FilesDownloadWorker.USER to user, diff --git a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt index cb8172655ccf..60d9eb16beb0 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt @@ -33,13 +33,12 @@ import androidx.core.app.NotificationCompat import androidx.work.Worker import androidx.work.WorkerParameters import com.nextcloud.client.account.User +import com.nextcloud.client.files.downloader.FilesDownloadHelper import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.files.services.FileDownloader import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.operations.DownloadType -import com.owncloud.android.ui.dialog.SendShareDialog import com.owncloud.android.ui.notifications.NotificationUtils import com.owncloud.android.utils.FileExportUtils import com.owncloud.android.utils.FileStorageUtils @@ -112,14 +111,15 @@ class FilesExportWork( } private fun downloadFile(ocFile: OCFile) { - val i = Intent(appContext, FileDownloader::class.java) - i.putExtra(FileDownloader.EXTRA_USER, user) - i.putExtra(FileDownloader.EXTRA_FILE, ocFile) - i.putExtra(SendShareDialog.PACKAGE_NAME, "") - i.putExtra(SendShareDialog.ACTIVITY_NAME, "") - i.putExtra(FileDownloader.DOWNLOAD_TYPE, DownloadType.EXPORT) - - FileDownloader(i) + FilesDownloadHelper().downloadFile( + user, + ocFile, + behaviour = "", + packageName = "", + activityName = "", + conflictUploadId = 0L, + downloadType = DownloadType.EXPORT + ) } private fun showErrorNotification(successfulExports: Int) { diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index e209d21bc301..e1d9ead64139 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -31,7 +31,7 @@ import com.nextcloud.android.files.FileLockingHelper; import com.nextcloud.client.account.User; import com.nextcloud.client.editimage.EditImageActivity; -import com.nextcloud.client.files.downloader.FileDownloadHelper; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.utils.EditorUtils; import com.owncloud.android.R; import com.owncloud.android.datamodel.FileDataStorageManager; @@ -380,8 +380,9 @@ private boolean anyFileSynchronizing() { if (componentsGetter != null && !files.isEmpty() && user != null) { OperationsServiceBinder opsBinder = componentsGetter.getOperationsServiceBinder(); FileUploaderBinder uploaderBinder = componentsGetter.getFileUploaderBinder(); + FilesDownloadWorker.FileDownloaderBinder downloaderBinder = componentsGetter.getFileDownloaderBinder(); synchronizing = anyFileSynchronizing(opsBinder) || // comparing local and remote - anyFileDownloading() || + anyFileDownloading(downloaderBinder) || anyFileUploading(uploaderBinder); } return synchronizing; @@ -397,14 +398,14 @@ private boolean anyFileSynchronizing(OperationsServiceBinder opsBinder) { return synchronizing; } - private boolean anyFileDownloading() { - for (OCFile file : files) { - if (FileDownloadHelper.Companion.instance().isDownloading(user, file)) { - return true; + private boolean anyFileDownloading(FilesDownloadWorker.FileDownloaderBinder downloaderBinder) { + boolean downloading = false; + if (downloaderBinder != null) { + for (Iterator iterator = files.iterator(); !downloading && iterator.hasNext(); ) { + downloading = downloaderBinder.isDownloading(user, iterator.next()); } } - - return false; + return downloading; } private boolean anyFileUploading(FileUploaderBinder uploaderBinder) { diff --git a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java deleted file mode 100644 index b537db5fbf9d..000000000000 --- a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java +++ /dev/null @@ -1,686 +0,0 @@ -/* - * ownCloud Android client application - * - * Copyright (C) 2012 Bartek Przybylski - * Copyright (C) 2012-2016 ownCloud Inc. - * - * 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.files.services; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.OnAccountsUpdateListener; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.graphics.BitmapFactory; -import android.os.Binder; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.Process; -import android.util.Pair; - -import com.nextcloud.client.account.User; -import com.nextcloud.client.account.UserAccountManager; -import com.nextcloud.client.files.downloader.DownloadTask; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; -import com.nextcloud.java.util.Optional; -import com.nextcloud.utils.extensions.IntentExtensionsKt; -import com.owncloud.android.MainApp; -import com.owncloud.android.R; -import com.owncloud.android.authentication.AuthenticatorActivity; -import com.owncloud.android.datamodel.FileDataStorageManager; -import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.datamodel.UploadsStorageManager; -import com.owncloud.android.lib.common.OwnCloudAccount; -import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; -import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; -import com.owncloud.android.lib.common.operations.RemoteOperationResult; -import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; -import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.lib.resources.files.FileUtils; -import com.owncloud.android.operations.DownloadFileOperation; -import com.owncloud.android.operations.DownloadType; -import com.owncloud.android.providers.DocumentsStorageProvider; -import com.owncloud.android.ui.activity.ConflictsResolveActivity; -import com.owncloud.android.ui.activity.FileActivity; -import com.owncloud.android.ui.activity.FileDisplayActivity; -import com.owncloud.android.ui.dialog.SendShareDialog; -import com.owncloud.android.ui.fragment.OCFileListFragment; -import com.owncloud.android.ui.notifications.NotificationUtils; -import com.owncloud.android.ui.preview.PreviewImageActivity; -import com.owncloud.android.ui.preview.PreviewImageFragment; -import com.owncloud.android.utils.ErrorMessageAdapter; -import com.owncloud.android.utils.MimeTypeUtil; -import com.owncloud.android.utils.theme.ViewThemeUtils; - -import java.io.File; -import java.security.SecureRandom; -import java.util.AbstractList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Vector; - -import javax.inject.Inject; - -import androidx.core.app.NotificationCompat; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import androidx.work.OneTimeWorkRequest; -import androidx.work.WorkManager; -import androidx.work.WorkRequest; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import static android.content.Context.NOTIFICATION_SERVICE; - -public class FileDownloader implements OnDatatransferProgressListener, OnAccountsUpdateListener { - - private final Context context = MainApp.getAppContext(); - private final Intent intent; - - private static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED"; - private static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH"; - - public static final String EXTRA_USER = "USER"; - public static final String EXTRA_FILE = "FILE"; - public static final String EXTRA_DOWNLOAD_RESULT = "RESULT"; - public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; - public static final String EXTRA_LINKED_TO_PATH = "LINKED_TO"; - public static final String ACCOUNT_NAME = "ACCOUNT_NAME"; - public static final String DOWNLOAD_TYPE = "DOWNLOAD_TYPE"; - - private static final int FOREGROUND_SERVICE_ID = 412; - - private static final String TAG = FileDownloader.class.getSimpleName(); - - private Looper mServiceLooper; - private ServiceHandler mServiceHandler; - private IBinder mBinder; - private OwnCloudClient mDownloadClient; - private Optional currentUser = Optional.empty(); - private FileDataStorageManager mStorageManager; - - private IndexedForest mPendingDownloads = new IndexedForest<>(); - - private DownloadFileOperation mCurrentDownload; - - private NotificationManager mNotificationManager; - private NotificationCompat.Builder mNotificationBuilder; - private int mLastPercent; - - private Notification mNotification; - - private long conflictUploadId; - - public boolean mStartedDownload = false; - - @Inject UserAccountManager accountManager; - @Inject UploadsStorageManager uploadsStorageManager; - @Inject LocalBroadcastManager localBroadcastManager; - @Inject ViewThemeUtils viewThemeUtils; - - public static String getDownloadAddedMessage() { - return FileDownloader.class.getName() + DOWNLOAD_ADDED_MESSAGE; - } - - public static String getDownloadFinishMessage() { - return FileDownloader.class.getName() + DOWNLOAD_FINISH_MESSAGE; - } - - public FileDownloader(Intent intent) { - this.intent = intent; - Log_OC.d(TAG, "Creating service"); - mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); - HandlerThread thread = new HandlerThread("FileDownloaderThread", Process.THREAD_PRIORITY_BACKGROUND); - thread.start(); - mServiceLooper = thread.getLooper(); - mServiceHandler = new ServiceHandler(mServiceLooper, this); - mBinder = new FileDownloaderBinder(); - - NotificationCompat.Builder builder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).setContentTitle( - context.getResources().getString(R.string.app_name)) - .setContentText(context.getResources().getString(R.string.foreground_service_download)) - .setSmallIcon(R.drawable.notification_icon) - .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.notification_icon)); - - - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - builder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD); - } - - mNotification = builder.build(); - - // add AccountsUpdatedListener - AccountManager am = AccountManager.get(context); - am.addOnAccountsUpdatedListener(this, null, false); - } - - @Override - protected void finalize() throws Throwable { - Log_OC.v(TAG, "Destroying service"); - mBinder = null; - mServiceHandler = null; - mServiceLooper.quit(); - mServiceLooper = null; - mNotificationManager = null; - - // remove AccountsUpdatedListener - AccountManager am = AccountManager.get(context); - am.removeOnAccountsUpdatedListener(this); - super.finalize(); - } - - public void download() { - final User user = IntentExtensionsKt.getParcelableArgument(intent, EXTRA_USER, User.class); - final OCFile file = IntentExtensionsKt.getParcelableArgument(intent, EXTRA_FILE, OCFile.class); - final String behaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); - - DownloadType downloadType = DownloadType.DOWNLOAD; - if (intent.hasExtra(DOWNLOAD_TYPE)) { - downloadType = IntentExtensionsKt.getSerializableArgument(intent, DOWNLOAD_TYPE, DownloadType.class); - } - String activityName = intent.getStringExtra(SendShareDialog.ACTIVITY_NAME); - String packageName = intent.getStringExtra(SendShareDialog.PACKAGE_NAME); - conflictUploadId = intent.getLongExtra(ConflictsResolveActivity.EXTRA_CONFLICT_UPLOAD_ID, -1); - AbstractList requestedDownloads = new Vector(); - try { - DownloadFileOperation newDownload = new DownloadFileOperation(user, - file, - behaviour, - activityName, - packageName, - context, - downloadType); - newDownload.addDatatransferProgressListener(this); - newDownload.addDatatransferProgressListener((FileDownloaderBinder) mBinder); - Pair putResult = mPendingDownloads.putIfAbsent(user.getAccountName(), - file.getRemotePath(), - newDownload); - if (putResult != null) { - String downloadKey = putResult.first; - requestedDownloads.add(downloadKey); - sendBroadcastNewDownload(newDownload, putResult.second); - } // else, file already in the queue of downloads; don't repeat the request - - } catch (IllegalArgumentException e) { - Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage()); - } - - if (requestedDownloads.size() > 0) { - Message msg = mServiceHandler.obtainMessage(); - // msg.arg1 = startId; - msg.obj = requestedDownloads; - mServiceHandler.sendMessage(msg); - } - } - - @Override - public void onAccountsUpdated(Account[] accounts) { - //review the current download and cancel it if its account doesn't exist - if (mCurrentDownload != null && !accountManager.exists(mCurrentDownload.getUser().toPlatformAccount())) { - mCurrentDownload.cancel(); - } - // The rest of downloads are cancelled when they try to start - } - - /** - * Binder to let client components to perform operations on the queue of downloads. - *

- * It provides by itself the available operations. - */ - public class FileDownloaderBinder2 extends Binder implements OnDatatransferProgressListener { - - /** - * Map of listeners that will be reported about progress of downloads from a - * {@link FileDownloaderBinder} - * instance. - */ - private Map mBoundListeners = - new HashMap(); - - - /** - * Cancels a pending or current download of a remote file. - * - * @param account ownCloud account where the remote file is stored. - * @param file A file in the queue of pending downloads - */ - public void cancel(Account account, OCFile file) { - Pair removeResult = - mPendingDownloads.remove(account.name, file.getRemotePath()); - DownloadFileOperation download = removeResult.first; - if (download != null) { - download.cancel(); - } else { - if (mCurrentDownload != null && currentUser.isPresent() && - mCurrentDownload.getRemotePath().startsWith(file.getRemotePath()) && - account.name.equals(currentUser.get().getAccountName())) { - mCurrentDownload.cancel(); - } - } - } - - /** - * Cancels all the downloads for an account - */ - public void cancel(String accountName) { - if (mCurrentDownload != null && mCurrentDownload.getUser().nameEquals(accountName)) { - mCurrentDownload.cancel(); - } - // Cancel pending downloads - cancelPendingDownloads(accountName); - } - - /** - * Returns True when the file described by 'file' in the ownCloud account 'account' - * is downloading or waiting to download. - * - * If 'file' is a directory, returns 'true' if any of its descendant files is downloading or - * waiting to download. - * - * @param user user where the remote file is stored. - * @param file A file that could be in the queue of downloads. - */ - public boolean isDownloading(User user, OCFile file) { - return user != null && file != null && mPendingDownloads.contains(user.getAccountName(), file.getRemotePath()); - } - - - /** - * Adds a listener interested in the progress of the download for a concrete file. - * - * @param listener Object to notify about progress of transfer. - * @param file {@link OCFile} of interest for listener. - */ - public void addDatatransferProgressListener(OnDatatransferProgressListener listener, OCFile file) { - if (file == null || listener == null) { - return; - } - mBoundListeners.put(file.getFileId(), listener); - } - - - /** - * Removes a listener interested in the progress of the download for a concrete file. - * - * @param listener Object to notify about progress of transfer. - * @param file {@link OCFile} of interest for listener. - */ - public void removeDatatransferProgressListener(OnDatatransferProgressListener listener, OCFile file) { - if (file == null || listener == null) { - return; - } - Long fileId = file.getFileId(); - if (mBoundListeners.get(fileId) == listener) { - mBoundListeners.remove(fileId); - } - } - - @Override - public void onTransferProgress(long progressRate, long totalTransferredSoFar, - long totalToTransfer, String fileName) { - OnDatatransferProgressListener boundListener = - mBoundListeners.get(mCurrentDownload.getFile().getFileId()); - if (boundListener != null) { - boundListener.onTransferProgress(progressRate, totalTransferredSoFar, - totalToTransfer, fileName); - } - } - - } - - /** - * Download worker. Performs the pending downloads in the order they were requested. - - * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}. - */ - private static class ServiceHandler extends Handler { - // don't make it a final class, and don't remove the static ; lint will warn about a - // possible memory leak - FileDownloader mService; - - public ServiceHandler(Looper looper, FileDownloader service) { - super(looper); - if (service == null) { - throw new IllegalArgumentException("Received invalid NULL in parameter 'service'"); - } - mService = service; - } - - @Override - public void handleMessage(Message msg) { - @SuppressWarnings("unchecked") - AbstractList requestedDownloads = (AbstractList) msg.obj; - if (msg.obj != null) { - Iterator it = requestedDownloads.iterator(); - while (it.hasNext()) { - String next = it.next(); - mService.downloadFile(next); - } - } - mService.mStartedDownload=false; - - (new Handler()).postDelayed(() -> { - if(!mService.mStartedDownload){ - mService.mNotificationManager.cancel(R.string.downloader_download_in_progress_ticker); - } - Log_OC.d(TAG, "Stopping after command with id " + msg.arg1); - mService.mNotificationManager.cancel(FOREGROUND_SERVICE_ID); - }, 2000); - } - } - - - void downloadFile(String downloadKey) { - - mStartedDownload = true; - mCurrentDownload = mPendingDownloads.get(downloadKey); - - if (mCurrentDownload != null) { - // Detect if the account exists - if (accountManager.exists(mCurrentDownload.getUser().toPlatformAccount())) { - notifyDownloadStart(mCurrentDownload); - RemoteOperationResult downloadResult = null; - try { - /// prepare client object to send the request to the ownCloud server - Account currentDownloadAccount = mCurrentDownload.getUser().toPlatformAccount(); - Optional currentDownloadUser = accountManager.getUser(currentDownloadAccount.name); - if (!currentUser.equals(currentDownloadUser)) { - currentUser = currentDownloadUser; - mStorageManager = new FileDataStorageManager(currentUser.get(), context.getContentResolver()); - } // else, reuse storage manager from previous operation - - // always get client from client manager, to get fresh credentials in case - // of update - OwnCloudAccount ocAccount = currentDownloadUser.get().toOwnCloudAccount(); - mDownloadClient = OwnCloudClientManagerFactory.getDefaultSingleton(). - getClientFor(ocAccount, context); - - - /// perform the download - downloadResult = mCurrentDownload.execute(mDownloadClient); - if (downloadResult.isSuccess() && mCurrentDownload.getDownloadType() == DownloadType.DOWNLOAD) { - saveDownloadedFile(); - } - - } catch (Exception e) { - Log_OC.e(TAG, "Error downloading", e); - downloadResult = new RemoteOperationResult(e); - - } finally { - Pair removeResult = mPendingDownloads.removePayload( - mCurrentDownload.getUser().getAccountName(), mCurrentDownload.getRemotePath()); - - if (downloadResult == null) { - downloadResult = new RemoteOperationResult(new RuntimeException("Error downloading…")); - } - - /// notify result - notifyDownloadResult(mCurrentDownload, downloadResult); - sendBroadcastDownloadFinished(mCurrentDownload, downloadResult, removeResult.second); - } - } else { - cancelPendingDownloads(mCurrentDownload.getUser().getAccountName()); - } - } - } - - - /** - * Updates the OC File after a successful download. - * - * TODO move to DownloadFileOperation - * unify with code from {@link DocumentsStorageProvider} and {@link DownloadTask}. - */ - private void saveDownloadedFile() { - OCFile file = mStorageManager.getFileById(mCurrentDownload.getFile().getFileId()); - - if (file == null) { - // try to get file via path, needed for overwriting existing files on conflict dialog - file = mStorageManager.getFileByDecryptedRemotePath(mCurrentDownload.getFile().getRemotePath()); - } - - if (file == null) { - Log_OC.e(this, "Could not save " + mCurrentDownload.getFile().getRemotePath()); - return; - } - - long syncDate = System.currentTimeMillis(); - file.setLastSyncDateForProperties(syncDate); - file.setLastSyncDateForData(syncDate); - file.setUpdateThumbnailNeeded(true); - file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp()); - file.setModificationTimestampAtLastSyncForData(mCurrentDownload.getModificationTimestamp()); - file.setEtag(mCurrentDownload.getEtag()); - file.setMimeType(mCurrentDownload.getMimeType()); - file.setStoragePath(mCurrentDownload.getSavePath()); - file.setFileLength(new File(mCurrentDownload.getSavePath()).length()); - file.setRemoteId(mCurrentDownload.getFile().getRemoteId()); - mStorageManager.saveFile(file); - if (MimeTypeUtil.isMedia(mCurrentDownload.getMimeType())) { - FileDataStorageManager.triggerMediaScan(file.getStoragePath(), file); - } - mStorageManager.saveConflict(file, null); - } - - /** - * Creates a status notification to show the download progress - * - * @param download Download operation starting. - */ - private void notifyDownloadStart(DownloadFileOperation download) { - /// create status notification with a progress bar - mLastPercent = 0; - mNotificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils); - mNotificationBuilder - .setSmallIcon(R.drawable.notification_icon) - .setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) - .setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) - .setOngoing(true) - .setProgress(100, 0, download.getSize() < 0) - .setContentText( - String.format(context.getString(R.string.downloader_download_in_progress_content), 0, - new File(download.getSavePath()).getName())); - - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - mNotificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD); - } - - /// includes a pending intent in the notification showing the details view of the file - Intent showDetailsIntent = null; - if (PreviewImageFragment.canBePreviewed(download.getFile())) { - showDetailsIntent = new Intent(context, PreviewImageActivity.class); - } else { - showDetailsIntent = new Intent(context, FileDisplayActivity.class); - } - showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, download.getFile()); - showDetailsIntent.putExtra(FileActivity.EXTRA_USER, download.getUser()); - showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - - mNotificationBuilder.setContentIntent(PendingIntent.getActivity(context, (int) System.currentTimeMillis(), - showDetailsIntent, PendingIntent.FLAG_IMMUTABLE)); - - - if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); - } - if (mNotificationManager != null) { - mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotificationBuilder.build()); - } - } - - - /** - * Callback method to update the progress bar in the status notification. - */ - @Override - public void onTransferProgress(long progressRate, long totalTransferredSoFar, - long totalToTransfer, String filePath) { - int percent = (int) (100.0 * ((double) totalTransferredSoFar) / ((double) totalToTransfer)); - if (percent != mLastPercent) { - mNotificationBuilder.setProgress(100, percent, totalToTransfer < 0); - String fileName = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1); - String text = String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName); - mNotificationBuilder.setContentText(text); - - if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); - } - - if (mNotificationManager != null) { - mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, - mNotificationBuilder.build()); - } - } - mLastPercent = percent; - } - - - /** - * Updates the status notification with the result of a download operation. - * - * @param downloadResult Result of the download operation. - * @param download Finished download operation - */ - @SuppressFBWarnings("DMI") - private void notifyDownloadResult(DownloadFileOperation download, - RemoteOperationResult downloadResult) { - if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); - } - - if (!downloadResult.isCancelled()) { - if (downloadResult.isSuccess()) { - if (conflictUploadId > 0) { - uploadsStorageManager.removeUpload(conflictUploadId); - } - // Dont show notification except an error has occured. - return; - } - int tickerId = downloadResult.isSuccess() ? - R.string.downloader_download_succeeded_ticker : R.string.downloader_download_failed_ticker; - - boolean needsToUpdateCredentials = ResultCode.UNAUTHORIZED == downloadResult.getCode(); - tickerId = needsToUpdateCredentials ? - R.string.downloader_download_failed_credentials_error : tickerId; - - mNotificationBuilder - .setTicker(context.getString(tickerId)) - .setContentTitle(context.getString(tickerId)) - .setAutoCancel(true) - .setOngoing(false) - .setProgress(0, 0, false); - - if (needsToUpdateCredentials) { - configureUpdateCredentialsNotification(download.getUser()); - - } else { - // TODO put something smart in showDetailsIntent - Intent showDetailsIntent = new Intent(); - mNotificationBuilder.setContentIntent(PendingIntent.getActivity(context, (int) System.currentTimeMillis(), - showDetailsIntent, PendingIntent.FLAG_IMMUTABLE)); - } - - mNotificationBuilder.setContentText(ErrorMessageAdapter.getErrorCauseMessage(downloadResult, - download, context.getResources())); - - if (mNotificationManager != null) { - mNotificationManager.notify((new SecureRandom()).nextInt(), mNotificationBuilder.build()); - - // Remove success notification - if (downloadResult.isSuccess()) { - // Sleep 2 seconds, so show the notification before remove it - NotificationUtils.cancelWithDelay(mNotificationManager, - R.string.downloader_download_succeeded_ticker, 2000); - } - } - } - } - - private void configureUpdateCredentialsNotification(User user) { - // let the user update credentials with one click - Intent updateAccountCredentials = new Intent(context, AuthenticatorActivity.class); - updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()); - updateAccountCredentials.putExtra( - AuthenticatorActivity.EXTRA_ACTION, - AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN - ); - updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND); - mNotificationBuilder.setContentIntent( - PendingIntent.getActivity(context, - (int) System.currentTimeMillis(), - updateAccountCredentials, - PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE) - ); - } - - - /** - * Sends a broadcast when a download finishes in order to the interested activities can - * update their view - * - * @param download Finished download operation - * @param downloadResult Result of the download operation - * @param unlinkedFromRemotePath Path in the downloads tree where the download was unlinked from - */ - private void sendBroadcastDownloadFinished( - DownloadFileOperation download, - RemoteOperationResult downloadResult, - String unlinkedFromRemotePath) { - - Intent end = new Intent(getDownloadFinishMessage()); - end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess()); - end.putExtra(ACCOUNT_NAME, download.getUser().getAccountName()); - end.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath()); - end.putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.getBehaviour()); - end.putExtra(SendShareDialog.ACTIVITY_NAME, download.getActivityName()); - end.putExtra(SendShareDialog.PACKAGE_NAME, download.getPackageName()); - if (unlinkedFromRemotePath != null) { - end.putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath); - } - end.setPackage(context.getPackageName()); - localBroadcastManager.sendBroadcast(end); - } - - - /** - * Sends a broadcast when a new download is added to the queue. - * - * @param download Added download operation - * @param linkedToRemotePath Path in the downloads tree where the download was linked to - */ - private void sendBroadcastNewDownload(DownloadFileOperation download, - String linkedToRemotePath) { - Intent added = new Intent(getDownloadAddedMessage()); - added.putExtra(ACCOUNT_NAME, download.getUser().getAccountName()); - added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath()); - added.putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath); - added.setPackage(context.getPackageName()); - localBroadcastManager.sendBroadcast(added); - } - - private void cancelPendingDownloads(String accountName) { - mPendingDownloads.remove(accountName); - } -} diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java index 80c4e2411a36..4efa2c0b7841 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -22,13 +22,12 @@ package com.owncloud.android.operations; import android.content.Context; -import android.content.Intent; import android.text.TextUtils; import com.nextcloud.client.account.User; +import com.nextcloud.client.files.downloader.FilesDownloadHelper; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.NameCollisionPolicy; import com.owncloud.android.lib.common.OwnCloudClient; @@ -317,11 +316,17 @@ private void requestForUpload(OCFile file) { * @param file OCFile object representing the file to download */ private void requestForDownload(OCFile file) { - Intent i = new Intent(mContext, FileDownloader.class); - i.putExtra(FileDownloader.EXTRA_USER, mUser); - i.putExtra(FileDownloader.EXTRA_FILE, file); + FilesDownloadHelper downloadHelper = new FilesDownloadHelper(); + + downloadHelper.downloadFile( + mUser, + file, + "", + null, + "", + "", + null); - new FileDownloader(i); mTransferWasRequested = true; } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index ec65a4cc7e3b..5bfd7ad0dc0d 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -25,7 +25,7 @@ import android.text.TextUtils; import com.nextcloud.client.account.User; -import com.nextcloud.client.files.downloader.FileDownloadHelper; +import com.nextcloud.client.files.downloader.FilesDownloadHelper; import com.owncloud.android.datamodel.DecryptedFolderMetadata; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; @@ -438,16 +438,32 @@ private void prepareOpsFromLocalKnowledge() throws OperationCancelledException { } } + private void syncContents() throws OperationCancelledException { startDirectDownloads(); startContentSynchronizations(mFilesToSyncContents); } - private void startDirectDownloads() { - FileDownloadHelper.Companion.instance().downloadFolder(mLocalFolder, - user, - mFilesForDirectDownload); + private void startDirectDownloads() throws OperationCancelledException { + for (OCFile file : mFilesForDirectDownload) { + synchronized(mCancellationRequested) { + if (mCancellationRequested.get()) { + throw new OperationCancelledException(); + } + + FilesDownloadHelper downloadHelper = new FilesDownloadHelper(); + + downloadHelper.downloadFile( + user, + file, + "", + null, + "", + "", + null); + } + } } /** diff --git a/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java b/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java index 24887f50587e..a7f10ffac956 100644 --- a/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java +++ b/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java @@ -307,7 +307,7 @@ private boolean hasServerChange(Document document) throws FileNotFoundException /** * Updates the OC File after a successful download. * - * TODO unify with code from {@link com.nextcloud.client.files.downloader.FileDownloadWorker} and {@link DownloadTask}. + * TODO unify with code from {@link com.nextcloud.client.files.downloader.FilesDownloadWorker} and {@link DownloadTask}. */ private void saveDownloadedFile(FileDataStorageManager storageManager, DownloadFileOperation dfo, OCFile file) { long syncDate = System.currentTimeMillis(); diff --git a/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java b/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java index 7a5d4d25f2b2..18329af5dc5d 100644 --- a/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java +++ b/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java @@ -28,7 +28,7 @@ import android.util.Pair; import com.nextcloud.client.account.User; -import com.nextcloud.client.files.downloader.FileDownloadWorker; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.IndexedForest; import com.owncloud.android.lib.common.OwnCloudAccount; @@ -169,9 +169,9 @@ public void cancel(Account account, OCFile file){ * this is a fast and ugly patch. */ private void sendBroadcastNewSyncFolder(Account account, String remotePath) { - Intent added = new Intent(FileDownloadWorker.Companion.getDownloadAddedMessage()); - added.putExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME, account.name); - added.putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, remotePath); + Intent added = new Intent(FilesDownloadWorker.Companion.getDownloadAddedMessage()); + added.putExtra(FilesDownloadWorker.ACCOUNT_NAME, account.name); + added.putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, remotePath); added.setPackage(mService.getPackageName()); LocalBroadcastManager.getInstance(mService.getApplicationContext()).sendBroadcast(added); } @@ -182,10 +182,10 @@ private void sendBroadcastNewSyncFolder(Account account, String remotePath) { */ private void sendBroadcastFinishedSyncFolder(Account account, String remotePath, boolean success) { - Intent finished = new Intent(FileDownloadWorker.Companion.getDownloadFinishMessage()); - finished.putExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME, account.name); - finished.putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, remotePath); - finished.putExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, success); + Intent finished = new Intent(FilesDownloadWorker.Companion.getDownloadFinishMessage()); + finished.putExtra(FilesDownloadWorker.ACCOUNT_NAME, account.name); + finished.putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, remotePath); + finished.putExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, success); finished.setPackage(mService.getPackageName()); LocalBroadcastManager.getInstance(mService.getApplicationContext()).sendBroadcast(finished); } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java index 0a9c2be2a19b..4b0ab8c6de2e 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java @@ -20,7 +20,7 @@ package com.owncloud.android.ui.activity; -import com.nextcloud.client.files.downloader.FileDownloadWorker; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.services.OperationsService.OperationsServiceBinder; @@ -30,11 +30,11 @@ public interface ComponentsGetter { /** * To be invoked when the parent activity is fully created to get a reference - * to the FileDownloadWorker. + * to the FileDownloader service API. */ - public FileDownloadWorker.FileDownloadProgressListener getFileDownloadProgressListener(); - + public FilesDownloadWorker.FileDownloaderBinder getFileDownloaderBinder(); + /** * To be invoked when the parent activity is fully created to get a reference * to the FileUploader service API. diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt index 830fee88af4f..4ac180376a21 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt @@ -21,13 +21,13 @@ import android.content.Intent import android.os.Bundle import android.widget.Toast import com.nextcloud.client.account.User +import com.nextcloud.client.files.downloader.FilesDownloadHelper import com.nextcloud.model.HTTPStatusCodes import com.nextcloud.utils.extensions.getParcelableArgument import com.owncloud.android.R import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.db.OCUpload -import com.owncloud.android.files.services.FileDownloader import com.owncloud.android.files.services.FileUploader import com.owncloud.android.files.services.NameCollisionPolicy import com.owncloud.android.lib.common.utils.Log_OC @@ -114,12 +114,17 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener Decision.KEEP_SERVER -> if (!shouldDeleteLocal()) { // Overwrite local file - val intent = Intent(baseContext, FileDownloader::class.java) - intent.putExtra(FileDownloader.EXTRA_USER, getUser().orElseThrow { RuntimeException() }) - intent.putExtra(FileDownloader.EXTRA_FILE, file) - intent.putExtra(EXTRA_CONFLICT_UPLOAD_ID, conflictUploadId) - - FileDownloader(intent) + file?.let { + FilesDownloadHelper().downloadFile( + user = getUser().orElseThrow { RuntimeException() }, + ocFile = file, + conflictUploadId = conflictUploadId, + behaviour = "", + packageName = "", + activityName = "", + downloadType = null + ) + } } else { uploadsStorageManager!!.removeUpload(upload) } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index 27ae30f27f45..d11c91f4a22b 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -43,6 +43,8 @@ import com.google.android.material.snackbar.Snackbar; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; +import com.nextcloud.client.files.downloader.FilesDownloadHelper; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.utils.EditorUtils; @@ -54,8 +56,6 @@ import com.owncloud.android.datamodel.ArbitraryDataProvider; import com.owncloud.android.datamodel.ArbitraryDataProviderImpl; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.files.services.FileDownloader; -import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.lib.common.OwnCloudAccount; @@ -166,7 +166,7 @@ public abstract class FileActivity extends DrawerActivity private boolean mResumed; - protected FileDownloaderBinder mDownloaderBinder; + protected FilesDownloadWorker.FileDownloaderBinder mDownloaderBinder; protected FileUploaderBinder mUploaderBinder; private ServiceConnection mDownloadServiceConnection; private ServiceConnection mUploadServiceConnection; @@ -206,6 +206,7 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mHandler = new Handler(); mFileOperationsHelper = new FileOperationsHelper(this, getUserAccountManager(), connectivityService, editorUtils); + User user = null; if (savedInstanceState != null) { mFile = BundleExtensionsKt.getParcelableArgument(savedInstanceState, FileActivity.EXTRA_FILE, OCFile.class); @@ -218,10 +219,11 @@ protected void onCreate(Bundle savedInstanceState) { viewThemeUtils.files.themeActionBar(this, actionBar, savedInstanceState.getString(KEY_ACTION_BAR_TITLE)); } } else { - User user = IntentExtensionsKt.getParcelableArgument(getIntent(), FileActivity.EXTRA_USER, User.class); + user = IntentExtensionsKt.getParcelableArgument(getIntent(), FileActivity.EXTRA_USER, User.class); mFile = IntentExtensionsKt.getParcelableArgument(getIntent(), FileActivity.EXTRA_FILE, OCFile.class); mFromNotification = getIntent().getBooleanExtra(FileActivity.EXTRA_FROM_NOTIFICATION, false); + if (user != null) { setUser(user); } @@ -233,8 +235,8 @@ protected void onCreate(Bundle savedInstanceState) { Context.BIND_AUTO_CREATE); mDownloadServiceConnection = newTransferenceServiceConnection(); - if (mDownloadServiceConnection != null) { - new FileDownloader(new Intent(this, FileDownloader.class)); + if (mDownloadServiceConnection != null && user != null) { + new FilesDownloadHelper().downloadFile(user, mFile, "", null, "", "", null); } mUploadServiceConnection = newTransferenceServiceConnection(); if (mUploadServiceConnection != null) { @@ -615,7 +617,7 @@ public void onServiceDisconnected(ComponentName component) { } @Override - public FileDownloaderBinder getFileDownloaderBinder() { + public FilesDownloadWorker.FileDownloaderBinder getFileDownloaderBinder() { return mDownloaderBinder; } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index ceb0ce1110f1..14298e498805 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -65,16 +65,14 @@ import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; import com.nextcloud.client.files.DeepLinkHandler; -import com.nextcloud.client.files.downloader.FileDownloadHelper; -import com.nextcloud.client.files.downloader.FileDownloadWorker; +import com.nextcloud.client.files.downloader.FilesDownloadHelper; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.client.media.PlayerServiceConnection; import com.nextcloud.client.network.ClientFactory; 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.WorkerState; -import com.nextcloud.model.WorkerStateLiveData; import com.nextcloud.utils.extensions.BundleExtensionsKt; import com.nextcloud.utils.extensions.IntentExtensionsKt; import com.nextcloud.utils.view.FastScrollUtils; @@ -96,7 +94,6 @@ import com.owncloud.android.lib.resources.files.SearchRemoteOperation; import com.owncloud.android.operations.CopyFileOperation; import com.owncloud.android.operations.CreateFolderOperation; -import com.owncloud.android.operations.DownloadType; import com.owncloud.android.operations.MoveFileOperation; import com.owncloud.android.operations.RefreshFolderOperation; import com.owncloud.android.operations.RemoveFileOperation; @@ -287,7 +284,6 @@ protected void onCreate(Bundle savedInstanceState) { checkStoragePath(); initSyncBroadcastReceiver(); - observeWorkerState(); } @SuppressWarnings("unchecked") @@ -688,12 +684,12 @@ protected void refreshDetailsFragmentIfVisible(String downloadEvent, String down // the user browsed to other file ; forget the automatic preview mWaitingToPreview = null; - } else if (downloadEvent.equals(FileDownloadWorker.Companion.getDownloadAddedMessage())) { + } else if (downloadEvent.equals(FilesDownloadWorker.Companion.getDownloadAddedMessage())) { // grant that the details fragment updates the progress bar detailsFragment.listenForTransferProgress(); detailsFragment.updateFileDetails(true, false); - } else if (downloadEvent.equals(FileDownloadWorker.Companion.getDownloadFinishMessage())) { + } else if (downloadEvent.equals(FilesDownloadWorker.Companion.getDownloadFinishMessage())) { // update the details panel boolean detailsFragmentChanged = false; if (waitedPreview) { @@ -1119,8 +1115,8 @@ protected void onResume() { localBroadcastManager.registerReceiver(mUploadFinishReceiver, uploadIntentFilter); // Listen for download messages - IntentFilter downloadIntentFilter = new IntentFilter(FileDownloadWorker.Companion.getDownloadAddedMessage()); - downloadIntentFilter.addAction(FileDownloadWorker.Companion.getDownloadFinishMessage()); + IntentFilter downloadIntentFilter = new IntentFilter(FilesDownloadWorker.Companion.getDownloadAddedMessage()); + downloadIntentFilter.addAction(FilesDownloadWorker.Companion.getDownloadFinishMessage()); mDownloadFinishReceiver = new DownloadFinishReceiver(); localBroadcastManager.registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); @@ -1421,7 +1417,7 @@ private boolean isAscendant(String linkedToRemotePath) { /** - * Class waiting for broadcast events from the {@link FileDownloadWorker} service. + * Class waiting for broadcast events from the {@link FilesDownloadWorker} service. *

* Updates the UI when a download is started or finished, provided that it is relevant for the current folder. */ @@ -1430,16 +1426,16 @@ private class DownloadFinishReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { boolean sameAccount = isSameAccount(intent); - String downloadedRemotePath = intent.getStringExtra(FileDownloadWorker.EXTRA_REMOTE_PATH); + String downloadedRemotePath = intent.getStringExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH); String downloadBehaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); boolean isDescendant = isDescendant(downloadedRemotePath); if (sameAccount && isDescendant) { - String linkedToRemotePath = intent.getStringExtra(FileDownloadWorker.EXTRA_LINKED_TO_PATH); + String linkedToRemotePath = intent.getStringExtra(FilesDownloadWorker.EXTRA_LINKED_TO_PATH); if (linkedToRemotePath == null || isAscendant(linkedToRemotePath)) { updateListOfFilesFragment(false); } - refreshDetailsFragmentIfVisible(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, false)); + refreshDetailsFragmentIfVisible(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, false)); } if (mWaitingToSend != null) { @@ -1472,7 +1468,7 @@ private boolean isAscendant(String linkedToRemotePath) { } private boolean isSameAccount(Intent intent) { - String accountName = intent.getStringExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME); + String accountName = intent.getStringExtra(FilesDownloadWorker.ACCOUNT_NAME); return accountName != null && getAccount() != null && accountName.equals(getAccount().name); } } @@ -1562,24 +1558,6 @@ public boolean isDrawerIndicatorAvailable() { return isRoot(getCurrentDir()); } - private void observeWorkerState() { - WorkerStateLiveData.Companion.instance().observe(this, state -> { - if (state instanceof WorkerState.Download) { - Log_OC.d(TAG, "Download worker started"); - handleDownloadWorkerState(); - } - }); - } - - private void handleDownloadWorkerState() { - if (mWaitingToPreview != null && getStorageManager() != null) { - mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); - if (mWaitingToPreview != null && !mWaitingToPreview.isDown()) { - requestForDownload(); - } - } - } - @Override protected ServiceConnection newTransferenceServiceConnection() { return new ListServiceConnection(); @@ -1592,13 +1570,22 @@ private class ListServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { - if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { + if (component.equals(new ComponentName(FileDisplayActivity.this, FilesDownloadWorker.class))) { + Log_OC.d(TAG, "Download service connected"); + mDownloaderBinder = (FilesDownloadWorker.FileDownloaderBinder) service; + if (mWaitingToPreview != null && getStorageManager() != null) { + // update the file + mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); + if (mWaitingToPreview != null && !mWaitingToPreview.isDown()) { + requestForDownload(); + } + } + } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service connected"); mUploaderBinder = (FileUploaderBinder) service; } else { return; } - // a new chance to get the mDownloadBinder through // getFileDownloadBinder() - THIS IS A MESS OCFileListFragment listOfFiles = getListOfFilesFragment(); @@ -1606,9 +1593,9 @@ public void onServiceConnected(ComponentName component, IBinder service) { IntentExtensionsKt.getParcelableArgument(getIntent(), EXTRA_FILE, OCFile.class) == null))) { listOfFiles.listDirectory(MainApp.isOnlyOnDevice(), false); } - Fragment leftFragment = getLeftFragment(); - if (leftFragment instanceof FileDetailFragment detailFragment) { + if (leftFragment instanceof FileDetailFragment) { + FileDetailFragment detailFragment = (FileDetailFragment) leftFragment; detailFragment.listenForTransferProgress(); detailFragment.updateFileDetails(false, false); } @@ -1616,9 +1603,9 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { - if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloadWorker.class))) { + if (component.equals(new ComponentName(FileDisplayActivity.this, FilesDownloadWorker.class))) { Log_OC.d(TAG, "Download service disconnected"); - fileDownloadProgressListener = null; + mDownloaderBinder = null; } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service disconnected"); mUploaderBinder = null; @@ -1896,7 +1883,10 @@ public void onTransferStateChanged(OCFile file, boolean downloading, boolean upl private void requestForDownload() { User user = getUser().orElseThrow(RuntimeException::new); - FileDownloadHelper.Companion.instance().downloadFileIfNotStartedBefore(user, mWaitingToPreview); + //if (!mWaitingToPreview.isDownloading()) { + if (!mDownloaderBinder.isDownloading(user, mWaitingToPreview)) { + new FilesDownloadHelper().downloadFile(user, mWaitingToPreview, "", null, "", "", null); + } } @Override @@ -1966,8 +1956,8 @@ public void run() { private void requestForDownload(OCFile file, String downloadBehaviour, String packageName, String activityName) { final User currentUser = getUser().orElseThrow(RuntimeException::new); - if (!FileDownloadHelper.Companion.instance().isDownloading(currentUser, file)) { - FileDownloadHelper.Companion.instance().downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); + if (!mDownloaderBinder.isDownloading(currentUser, mWaitingToPreview)) { + new FilesDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, null, activityName, packageName, null); } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 955c240d0857..598a8e740772 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -41,12 +41,10 @@ import com.google.common.collect.Sets; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; -import com.nextcloud.client.files.downloader.FileDownloadHelper; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.onboarding.FirstRunActivity; import com.nextcloud.java.util.Optional; -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; @@ -58,7 +56,6 @@ import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.UserInfo; import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.operations.DownloadFileOperation; import com.owncloud.android.services.OperationsService; import com.owncloud.android.ui.adapter.UserListAdapter; import com.owncloud.android.ui.adapter.UserListItem; @@ -108,6 +105,7 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap private final Handler handler = new Handler(); private String accountName; private UserListAdapter userListAdapter; + private ServiceConnection downloadServiceConnection; private ServiceConnection uploadServiceConnection; private Set originalUsers; private String originalCurrentUser; @@ -115,9 +113,6 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap private ArbitraryDataProvider arbitraryDataProvider; private boolean multipleAccountsSupported; - private String workerAccountName; - private DownloadFileOperation workerCurrentDownload; - @Inject BackgroundJobManager backgroundJobManager; @Inject UserAccountManager accountManager; @@ -165,7 +160,6 @@ protected void onCreate(Bundle savedInstanceState) { recyclerView.setAdapter(userListAdapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); initializeComponentGetters(); - observeWorkerState(); } @@ -247,6 +241,11 @@ private boolean hasCurrentAccountChanged() { * Initialize ComponentsGetters. */ private void initializeComponentGetters() { + downloadServiceConnection = newTransferenceServiceConnection(); + if (downloadServiceConnection != null) { + // FIXME check this usage + // bindService(new Intent(this, FileDownloader.class), downloadServiceConnection, Context.BIND_AUTO_CREATE); + } uploadServiceConnection = newTransferenceServiceConnection(); if (uploadServiceConnection != null) { bindService(new Intent(this, FileUploader.class), uploadServiceConnection, @@ -341,8 +340,9 @@ public void run(AccountManagerFuture future) { if (mUploaderBinder != null) { mUploaderBinder.cancel(accountName); } - - FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); + if (mDownloaderBinder != null) { + mDownloaderBinder.cancel(accountName); + } } User currentUser = getUserAccountManager().getUser(); @@ -374,6 +374,10 @@ public void run(AccountManagerFuture future) { @Override protected void onDestroy() { + if (downloadServiceConnection != null) { + unbindService(downloadServiceConnection); + downloadServiceConnection = null; + } if (uploadServiceConnection != null) { unbindService(uploadServiceConnection); uploadServiceConnection = null; @@ -431,8 +435,9 @@ private void performAccountRemoval(User user) { if (mUploaderBinder != null) { mUploaderBinder.cancel(user); } - - FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); + if (mDownloaderBinder != null) { + mDownloaderBinder.cancel(user.getAccountName()); + } backgroundJobManager.startAccountRemovalJob(user.getAccountName(), false); @@ -517,16 +522,6 @@ public void onOptionItemClicked(User user, View view) { } } - private void observeWorkerState() { - WorkerStateLiveData.Companion.instance().observe(this, state -> { - if (state instanceof WorkerState.Download) { - Log_OC.d(TAG, "Download worker started"); - workerAccountName = ((WorkerState.Download) state).getUser().getAccountName(); - workerCurrentDownload = ((WorkerState.Download) state).getCurrentDownload(); - } - }); - } - @Override public void onAccountClicked(User user) { openAccount(user); @@ -539,7 +534,11 @@ private class ManageAccountsServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { - if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { + + if (component.equals(new ComponentName(ManageAccountsActivity.this, FilesDownloadWorker.class))) { + mDownloaderBinder = (FilesDownloadWorker.FileDownloaderBinder) service; + + } else if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service connected"); mUploaderBinder = (FileUploader.FileUploaderBinder) service; } @@ -547,7 +546,10 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { - if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { + if (component.equals(new ComponentName(ManageAccountsActivity.this, FilesDownloadWorker.class))) { + Log_OC.d(TAG, "Download service suddenly disconnected"); + mDownloaderBinder = null; + } else if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service suddenly disconnected"); mUploaderBinder = null; } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index cecc01838c49..6aa4af298815 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -44,7 +44,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; -import com.nextcloud.client.files.downloader.FileDownloadHelper; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ClientFactory; import com.nextcloud.client.network.ConnectivityService; @@ -502,7 +502,7 @@ public void updateFileDetails(OCFile file, User user) { * TODO Remove parameter when the transferring state of files is kept in database. * * @param transferring Flag signaling if the file should be considered as downloading or uploading, although - * {@link FileDownloadHelper#isDownloading(User, OCFile)} and + * {@link com.nextcloud.client.files.downloader.FilesDownloadWorker.FileDownloaderBinder#isDownloading(User, OCFile)} and * {@link FileUploaderBinder#isUploading(User, OCFile)} return false. * @param refresh If 'true', try to refresh the whole file from the database */ @@ -534,9 +534,10 @@ public void updateFileDetails(boolean transferring, boolean refresh) { setFavoriteIconStatus(file.isFavorite()); // configure UI for depending upon local state of the file + FilesDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); if (transferring - || (FileDownloadHelper.Companion.instance().isDownloading(user, file)) + || (downloaderBinder != null && downloaderBinder.isDownloading(user, file)) || (uploaderBinder != null && uploaderBinder.isUploading(user, file))) { setButtonsForTransferring(); @@ -658,8 +659,10 @@ private void setButtonsForTransferring() { // show the progress bar for the transfer binding.progressBlock.setVisibility(View.VISIBLE); binding.progressText.setVisibility(View.VISIBLE); + FilesDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); - if (FileDownloadHelper.Companion.instance().isDownloading(user, getFile())) { + //if (getFile().isDownloading()) { + if (downloaderBinder != null && downloaderBinder.isDownloading(user, getFile())) { binding.progressText.setText(R.string.downloader_download_in_progress_ticker); } else { if (uploaderBinder != null && uploaderBinder.isUploading(user, getFile())) { @@ -691,9 +694,9 @@ private void setButtonsForRemote() { public void listenForTransferProgress() { if (progressListener != null) { - if (containerActivity.getFileDownloadProgressListener() != null) { - containerActivity.getFileDownloadProgressListener(). - addDataTransferProgressListener(progressListener, getFile()); + if (containerActivity.getFileDownloaderBinder() != null) { + containerActivity.getFileDownloaderBinder(). + addDatatransferProgressListener(progressListener, getFile()); } if (containerActivity.getFileUploaderBinder() != null) { containerActivity.getFileUploaderBinder(). @@ -706,9 +709,9 @@ public void listenForTransferProgress() { private void leaveTransferProgress() { if (progressListener != null) { - if (containerActivity.getFileDownloadProgressListener() != null) { - containerActivity.getFileDownloadProgressListener(). - removeDataTransferProgressListener(progressListener, getFile()); + if (containerActivity.getFileDownloaderBinder() != null) { + containerActivity.getFileDownloaderBinder(). + removeDatatransferProgressListener(progressListener, getFile()); } if (containerActivity.getFileUploaderBinder() != null) { containerActivity.getFileUploaderBinder(). diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 69ee619382b2..a3e7411dc2bf 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -47,7 +47,7 @@ import com.nextcloud.client.account.CurrentAccountProvider; import com.nextcloud.client.account.User; -import com.nextcloud.client.files.downloader.FileDownloadHelper; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.java.util.Optional; @@ -996,10 +996,11 @@ public void cancelTransference(OCFile file) { } } - if (FileDownloadHelper.Companion.instance().isDownloading(currentUser, file)) { - FileDownloadHelper.Companion.instance().cancelPendingOrCurrentDownloads(currentUser, file); + // for both files and folders + FilesDownloadWorker.FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder(); + if (downloaderBinder != null && downloaderBinder.isDownloading(currentUser, file)) { + downloaderBinder.cancel(currentUser.toPlatformAccount(), file); } - FileUploaderBinder uploaderBinder = fileActivity.getFileUploaderBinder(); if (uploaderBinder != null && uploaderBinder.isUploading(currentUser, file)) { uploaderBinder.cancel(currentUser.toPlatformAccount(), file); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 1152562ae92d..e83786b39347 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -37,6 +37,8 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; +import com.nextcloud.client.files.downloader.FilesDownloadHelper; +import com.nextcloud.client.files.downloader.FilesDownloadWorker; import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.java.util.Optional; import com.nextcloud.utils.extensions.IntentExtensionsKt; @@ -45,8 +47,6 @@ import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.VirtualFolderType; -import com.owncloud.android.files.services.FileDownloader; -import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.lib.common.operations.OnRemoteOperationListener; @@ -311,8 +311,8 @@ private class PreviewImageServiceConnection implements ServiceConnection { public void onServiceConnected(ComponentName component, IBinder service) { if (component.equals(new ComponentName(PreviewImageActivity.this, - FileDownloader.class))) { - mDownloaderBinder = (FileDownloaderBinder) service; + FilesDownloadWorker.class))) { + mDownloaderBinder = (FilesDownloadWorker.FileDownloaderBinder) service; if (mRequestWaitingForBinder) { mRequestWaitingForBinder = false; Log_OC.d(TAG, "Simulating reselection of current page after connection " + @@ -331,7 +331,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { if (component.equals(new ComponentName(PreviewImageActivity.this, - FileDownloader.class))) { + FilesDownloadWorker.class))) { Log_OC.d(TAG, "Download service suddenly disconnected"); mDownloaderBinder = null; } else if (component.equals(new ComponentName(PreviewImageActivity.this, @@ -359,7 +359,7 @@ protected void onResume() { super.onResume(); mDownloadFinishReceiver = new DownloadFinishReceiver(); - IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.getDownloadFinishMessage()); + IntentFilter downloadIntentFilter = new IntentFilter(FilesDownloadWorker.Companion.getDownloadFinishMessage()); localBroadcastManager.registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); mUploadFinishReceiver = new UploadFinishReceiver(); @@ -413,13 +413,7 @@ public void requestForDownload(OCFile file, String downloadBehaviour) { } else if (!mDownloaderBinder.isDownloading(getUserAccountManager().getUser(), file)) { final User user = getUser().orElseThrow(RuntimeException::new); - Intent i = new Intent(this, FileDownloader.class); - i.putExtra(FileDownloader.EXTRA_USER, user); - i.putExtra(FileDownloader.EXTRA_FILE, file); - if (downloadBehaviour != null) { - i.putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, downloadBehaviour); - } - new FileDownloader(i); + new FilesDownloadHelper().downloadFile(user, file, downloadBehaviour, null, "", "", null); } } @@ -484,7 +478,7 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse } /** - * Class waiting for broadcast events from the {@link FileDownloader} service. + * Class waiting for broadcast events from the {@link FilesDownloadWorker} service. * * Updates the UI when a download is started or finished, provided that it is relevant for the * folder displayed in the gallery. @@ -504,12 +498,12 @@ public void onReceive(Context context, Intent intent) { } private void previewNewImage(Intent intent) { - String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME); - String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH); + String accountName = intent.getStringExtra(FilesDownloadWorker.ACCOUNT_NAME); + String downloadedRemotePath = intent.getStringExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH); String downloadBehaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); if (getAccount().name.equals(accountName) && downloadedRemotePath != null) { OCFile file = getStorageManager().getFileByPath(downloadedRemotePath); - boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false); + boolean downloadWasFine = intent.getBooleanExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, false); if (EditImageActivity.OPEN_IMAGE_EDITOR.equals(downloadBehaviour)) { startImageEditor(file); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index 2b685b8a8c59..0b98dae862f4 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -53,6 +53,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; +import com.nextcloud.client.files.downloader.FilesDownloadHelper; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.media.ExoplayerListener; import com.nextcloud.client.media.NextcloudExoPlayer; @@ -66,7 +67,6 @@ import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.ThumbnailsCacheManager; import com.owncloud.android.files.StreamMediaFileOperation; -import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; @@ -479,10 +479,7 @@ public void onFileActionChosen(final int itemId) { backgroundJobManager); } else if (itemId == R.id.action_download_file) { if (!containerActivity.getFileDownloaderBinder().isDownloading(user, getFile())) { - Intent i = new Intent(requireActivity(), FileDownloader.class); - i.putExtra(FileDownloader.EXTRA_USER, user); - i.putExtra(FileDownloader.EXTRA_FILE, getFile()); - new FileDownloader(i); + new FilesDownloadHelper().downloadFile(user, getFile(), "", null, "", "", null); } } } From 412319276ddb67a785932816d16276e397ebfd17 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 12:34:41 +0100 Subject: [PATCH 098/189] Overload downloadFile functions Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadHelper.kt | 48 +++++++++++++++++++ .../nextcloud/client/jobs/FilesExportWork.kt | 6 +-- .../operations/SynchronizeFileOperation.java | 7 +-- .../SynchronizeFolderOperation.java | 9 +--- .../ui/activity/ConflictsResolveActivity.kt | 10 ++-- .../android/ui/activity/FileActivity.java | 2 +- .../ui/activity/FileDisplayActivity.java | 2 +- .../ui/preview/PreviewImageActivity.java | 2 +- .../ui/preview/PreviewMediaFragment.java | 2 +- 9 files changed, 58 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt index 71f833c07bdc..8a0a855f84b5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt @@ -41,6 +41,54 @@ class FilesDownloadHelper { MainApp.getAppComponent().inject(this) } + fun downloadFile(user: User, ocFile: OCFile) { + backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + "", + null, + "", + "", + null + ) + } + + fun downloadFile(user: User, ocFile: OCFile, behaviour: String) { + backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + behaviour, + null, + "", + "", + null + ) + } + + fun downloadFile(user: User, ocFile: OCFile, downloadType: DownloadType) { + backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + "", + downloadType, + "", + "", + null + ) + } + + fun downloadFile(user: User, ocFile: OCFile, conflictUploadId: Long) { + backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + "", + null, + "", + "", + conflictUploadId + ) + } + fun downloadFile( user: User, ocFile: OCFile, diff --git a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt index 60d9eb16beb0..797cea1969e4 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt @@ -114,11 +114,7 @@ class FilesExportWork( FilesDownloadHelper().downloadFile( user, ocFile, - behaviour = "", - packageName = "", - activityName = "", - conflictUploadId = 0L, - downloadType = DownloadType.EXPORT + DownloadType.EXPORT ) } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java index 4efa2c0b7841..1d9228dab52d 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -320,12 +320,7 @@ private void requestForDownload(OCFile file) { downloadHelper.downloadFile( mUser, - file, - "", - null, - "", - "", - null); + file); mTransferWasRequested = true; } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index 5bfd7ad0dc0d..8aa1e07a765e 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -454,14 +454,7 @@ private void startDirectDownloads() throws OperationCancelledException { FilesDownloadHelper downloadHelper = new FilesDownloadHelper(); - downloadHelper.downloadFile( - user, - file, - "", - null, - "", - "", - null); + downloadHelper.downloadFile(user, file); } } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt index 4ac180376a21..5d18e9698380 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt @@ -116,13 +116,9 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener // Overwrite local file file?.let { FilesDownloadHelper().downloadFile( - user = getUser().orElseThrow { RuntimeException() }, - ocFile = file, - conflictUploadId = conflictUploadId, - behaviour = "", - packageName = "", - activityName = "", - downloadType = null + getUser().orElseThrow { RuntimeException() }, + file, + conflictUploadId ) } } else { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index d11c91f4a22b..2a89b567e764 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -236,7 +236,7 @@ protected void onCreate(Bundle savedInstanceState) { mDownloadServiceConnection = newTransferenceServiceConnection(); if (mDownloadServiceConnection != null && user != null) { - new FilesDownloadHelper().downloadFile(user, mFile, "", null, "", "", null); + new FilesDownloadHelper().downloadFile(user, mFile); } mUploadServiceConnection = newTransferenceServiceConnection(); if (mUploadServiceConnection != null) { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 14298e498805..106dac2e027e 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1885,7 +1885,7 @@ private void requestForDownload() { User user = getUser().orElseThrow(RuntimeException::new); //if (!mWaitingToPreview.isDownloading()) { if (!mDownloaderBinder.isDownloading(user, mWaitingToPreview)) { - new FilesDownloadHelper().downloadFile(user, mWaitingToPreview, "", null, "", "", null); + new FilesDownloadHelper().downloadFile(user, mWaitingToPreview); } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index e83786b39347..fe11f92933fc 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -413,7 +413,7 @@ public void requestForDownload(OCFile file, String downloadBehaviour) { } else if (!mDownloaderBinder.isDownloading(getUserAccountManager().getUser(), file)) { final User user = getUser().orElseThrow(RuntimeException::new); - new FilesDownloadHelper().downloadFile(user, file, downloadBehaviour, null, "", "", null); + new FilesDownloadHelper().downloadFile(user, file, downloadBehaviour); } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index 0b98dae862f4..d42ebb0255cc 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -479,7 +479,7 @@ public void onFileActionChosen(final int itemId) { backgroundJobManager); } else if (itemId == R.id.action_download_file) { if (!containerActivity.getFileDownloaderBinder().isDownloading(user, getFile())) { - new FilesDownloadHelper().downloadFile(user, getFile(), "", null, "", "", null); + new FilesDownloadHelper().downloadFile(user, getFile()); } } } From 9d2271a38094d8b42333452b6b86a9991644daa5 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 15:23:34 +0100 Subject: [PATCH 099/189] Overload downloadFile functions Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 29 +++++++++++++++---- .../client/jobs/BackgroundJobManagerImpl.kt | 12 ++++++-- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index dfdf51781a96..123f94fae438 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -41,6 +41,10 @@ import androidx.core.app.NotificationCompat import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters +import com.google.gson.Gson +import com.google.gson.JsonElement +import com.google.gson.JsonSerializationContext +import com.google.gson.JsonSerializer import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional @@ -86,6 +90,8 @@ class FilesDownloadWorker( companion object { private val TAG = FilesDownloadWorker::class.java.simpleName + + var user: User? = null const val USER = "USER" const val FILE = "FILE" const val BEHAVIOUR = "BEHAVIOUR" @@ -122,13 +128,22 @@ class FilesDownloadWorker( private var startedDownload = false private var storageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null + private val gson = Gson() override fun doWork(): Result { return try { - conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long - val user = inputData.keyValueMap[USER] as User - val file = inputData.keyValueMap[FILE] as OCFile - val downloadType = inputData.keyValueMap[DOWNLOAD_TYPE] as DownloadType + conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? + val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) + val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? + val downloadType = if (downloadTypeAsString != null) { + if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { + DownloadType.DOWNLOAD + } else { + DownloadType.EXPORT + } + } else { + null + } val behaviour = inputData.keyValueMap[BEHAVIOUR] as String val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String val packageName = inputData.keyValueMap[PACKAGE_NAME] as String @@ -137,10 +152,12 @@ class FilesDownloadWorker( showDownloadingFilesNotification() addAccountUpdateListener() - requestDownloads(user, file, behaviour, downloadType, activityName, packageName) + requestDownloads(user!!, file, behaviour, downloadType, activityName, packageName) + Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() } catch (t: Throwable) { + Log_OC.e(TAG, "Error caught at FilesDownloadWorker(): " + t.localizedMessage) Result.failure() } } @@ -149,7 +166,7 @@ class FilesDownloadWorker( user: User, file: OCFile, behaviour: String, - downloadType: DownloadType, + downloadType: DownloadType?, activityName: String, packageName: String, ) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 943e9c6d0fc3..249542077afd 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -34,6 +34,7 @@ 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 @@ -517,16 +518,21 @@ internal class BackgroundJobManagerImpl( packageName: String, conflictUploadId: Long? ) { + val gson = Gson() + + // FIXME user interface cant serialize and deserialize val data = workDataOf( - FilesDownloadWorker.USER to user, - FilesDownloadWorker.FILE to ocFile, + //FilesDownloadWorker.USER to gson.toJson(user), + FilesDownloadWorker.FILE to gson.toJson(ocFile), FilesDownloadWorker.BEHAVIOUR to behaviour, - FilesDownloadWorker.DOWNLOAD_TYPE to downloadType, + FilesDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), FilesDownloadWorker.ACTIVITY_NAME to activityName, FilesDownloadWorker.PACKAGE_NAME to packageName, FilesDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId, ) + FilesDownloadWorker.user = user + val request = oneTimeRequestBuilder(FilesDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .setInputData(data) .build() From dc0bcefcf329dd325807811c1fc3e2875cb6f085 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 12:56:08 +0100 Subject: [PATCH 100/189] Rebase master Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 179 +++++++----------- .../ui/activity/ManageAccountsActivity.java | 4 +- .../ui/fragment/FileDetailFragment.java | 4 +- .../ui/helpers/FileOperationsHelper.java | 2 +- .../ui/preview/FileDownloadFragment.java | 8 +- 5 files changed, 74 insertions(+), 123 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index 123f94fae438..787bcb4f10ff 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -32,19 +32,13 @@ import android.content.Intent import android.graphics.BitmapFactory import android.os.Binder import android.os.Build -import android.os.Handler import android.os.IBinder -import android.os.Looper -import android.os.Message import android.util.Pair import androidx.core.app.NotificationCompat import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters import com.google.gson.Gson -import com.google.gson.JsonElement -import com.google.gson.JsonSerializationContext -import com.google.gson.JsonSerializer import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional @@ -124,7 +118,6 @@ class FilesDownloadWorker( private val pendingDownloads = IndexedForest() private var downloadBinder: IBinder? = null private var currentUser = Optional.empty() - private val workerHandler: WorkerHandler? = null private var startedDownload = false private var storageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null @@ -132,27 +125,16 @@ class FilesDownloadWorker( override fun doWork(): Result { return try { - conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? - val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) - val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? - val downloadType = if (downloadTypeAsString != null) { - if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { - DownloadType.DOWNLOAD - } else { - DownloadType.EXPORT - } - } else { - null - } - val behaviour = inputData.keyValueMap[BEHAVIOUR] as String - val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String - val packageName = inputData.keyValueMap[PACKAGE_NAME] as String - - downloadBinder = FileDownloaderBinder() + val requestDownloads = getRequestDownloads() showDownloadingFilesNotification() addAccountUpdateListener() - requestDownloads(user!!, file, behaviour, downloadType, activityName, packageName) + + val it: Iterator = requestDownloads.iterator() + while (it.hasNext()) { + val next = it.next() + downloadFile(next) + } Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() @@ -162,14 +144,23 @@ class FilesDownloadWorker( } } - private fun requestDownloads( - user: User, - file: OCFile, - behaviour: String, - downloadType: DownloadType?, - activityName: String, - packageName: String, - ) { + private fun getRequestDownloads(): AbstractList { + conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? + val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) + val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? + val downloadType = if (downloadTypeAsString != null) { + if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { + DownloadType.DOWNLOAD + } else { + DownloadType.EXPORT + } + } else { + null + } + val behaviour = inputData.keyValueMap[BEHAVIOUR] as String + val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String + val packageName = inputData.keyValueMap[PACKAGE_NAME] as String + val requestedDownloads: AbstractList = Vector() try { val operation = DownloadFileOperation( @@ -184,7 +175,7 @@ class FilesDownloadWorker( operation.addDatatransferProgressListener(this) operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder?) val putResult: Pair = pendingDownloads.putIfAbsent( - user.accountName, + user?.accountName, file.remotePath, operation ) @@ -196,15 +187,7 @@ class FilesDownloadWorker( Log_OC.e(TAG, "Not enough information provided in intent: " + e.message) } - if (requestedDownloads.size > 0) { - val msg: Message? = workerHandler?.obtainMessage() - // msg.arg1 = startId; - msg?.obj = requestedDownloads - - msg?.let { - workerHandler?.sendMessage(msg) - } - } + return requestedDownloads } private fun downloadFile(downloadKey: String) { @@ -266,16 +249,24 @@ class FilesDownloadWorker( } } - private fun saveDownloadedFile() { + private fun getCurrentFile(): OCFile? { var file: OCFile? = currentDownload?.file?.fileId?.let { storageManager?.getFileById(it) } + if (file == null) { - // try to get file via path, needed for overwriting existing files on conflict dialog file = storageManager?.getFileByDecryptedRemotePath(currentDownload?.file?.remotePath) } + if (file == null) { Log_OC.e(this, "Could not save " + currentDownload?.file?.remotePath) - return + return null } + + return file + } + + private fun saveDownloadedFile() { + val file = getCurrentFile() ?: return + val syncDate = System.currentTimeMillis() file.lastSyncDateForProperties = syncDate file.lastSyncDateForData = syncDate @@ -325,10 +316,12 @@ class FilesDownloadWorker( if (!downloadResult.isCancelled) { if (downloadResult.isSuccess) { - if (conflictUploadId!! > 0) { - uploadsStorageManager.removeUpload(conflictUploadId!!) + conflictUploadId?.let { + if (it > 0) { + uploadsStorageManager.removeUpload(it) + } } - // Dont show notification except an error has occured. + return } var tickerId = @@ -363,14 +356,12 @@ class FilesDownloadWorker( ) ) - if (notificationManager != null) { - notificationManager?.notify(SecureRandom().nextInt(), notificationBuilder?.build()) - if (downloadResult.isSuccess) { - NotificationUtils.cancelWithDelay( - notificationManager, - R.string.downloader_download_succeeded_ticker, 2000 - ) - } + notificationManager?.notify(SecureRandom().nextInt(), notificationBuilder?.build()) + if (downloadResult.isSuccess) { + NotificationUtils.cancelWithDelay( + notificationManager, + R.string.downloader_download_succeeded_ticker, 2000 + ) } } } @@ -432,9 +423,8 @@ class FilesDownloadWorker( if (notificationManager == null) { notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager } - if (notificationManager != null) { - notificationManager?.notify(R.string.downloader_download_in_progress_ticker, notificationBuilder?.build()) - } + + notificationManager?.notify(R.string.downloader_download_in_progress_ticker, notificationBuilder?.build()) } private fun showDownloadingFilesNotification() { @@ -474,7 +464,7 @@ class FilesDownloadWorker( } override fun onAccountsUpdated(accounts: Array?) { - if (currentDownload != null && !accountManager.exists(currentDownload?.user?.toPlatformAccount())) { + if (!accountManager.exists(currentDownload?.user?.toPlatformAccount())) { currentDownload?.cancel() } } @@ -496,31 +486,18 @@ class FilesDownloadWorker( if (notificationManager == null) { notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager } - if (notificationManager != null) { - notificationManager?.notify( - R.string.downloader_download_in_progress_ticker, - notificationBuilder?.build() - ) - } + notificationManager?.notify( + R.string.downloader_download_in_progress_ticker, + notificationBuilder?.build() + ) } lastPercent = percent } inner class FileDownloaderBinder : Binder(), OnDatatransferProgressListener { - /** - * Map of listeners that will be reported about progress of downloads from a - * [FileDownloaderBinder] - * instance. - */ - private val mBoundListeners: MutableMap = HashMap() - - /** - * Cancels a pending or current download of a remote file. - * - * @param account ownCloud account where the remote file is stored. - * @param file A file in the queue of pending downloads - */ - fun cancel(account: Account, file: OCFile) { + private val boundListeners: MutableMap = HashMap() + + fun cancelPendingOrCurrentDownloads(account: Account, file: OCFile) { val removeResult: Pair = pendingDownloads.remove(account.name, file.remotePath) val download = removeResult.first @@ -535,10 +512,7 @@ class FilesDownloadWorker( } } - /** - * Cancels all the downloads for an account - */ - fun cancel(accountName: String?) { + fun cancelAllDownloadsForAccount(accountName: String?) { if (currentDownload != null && currentDownload?.user?.nameEquals(accountName) == true) { currentDownload?.cancel() } @@ -550,20 +524,20 @@ class FilesDownloadWorker( return user != null && file != null && pendingDownloads.contains(user.accountName, file.remotePath) } - fun addDatatransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { + fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { if (file == null || listener == null) { return } - mBoundListeners[file.fileId] = listener + boundListeners[file.fileId] = listener } - fun removeDatatransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { + fun removeDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { if (file == null || listener == null) { return } val fileId = file.fileId - if (mBoundListeners[fileId] === listener) { - mBoundListeners.remove(fileId) + if (boundListeners[fileId] === listener) { + boundListeners.remove(fileId) } } @@ -571,34 +545,11 @@ class FilesDownloadWorker( progressRate: Long, totalTransferredSoFar: Long, totalToTransfer: Long, fileName: String ) { - val boundListener = mBoundListeners[currentDownload?.file?.fileId] + val boundListener = boundListeners[currentDownload?.file?.fileId] boundListener?.onTransferProgress( progressRate, totalTransferredSoFar, totalToTransfer, fileName ) } } - - private class WorkerHandler(looper: Looper, private val worker: FilesDownloadWorker) : Handler(looper) { - override fun handleMessage(msg: Message) { - val requestedDownloads = msg.obj as AbstractList - - if (msg.obj != null) { - val it: Iterator = requestedDownloads.iterator() - while (it.hasNext()) { - val next = it.next() - worker.downloadFile(next) - } - } - - worker.startedDownload = false - - Handler(Looper.getMainLooper()).postDelayed({ - if (!worker.startedDownload) { - worker.notificationManager?.cancel(R.string.downloader_download_in_progress_ticker) - } - Log_OC.d(TAG, "Stopping after command with id " + msg.arg1) - }, 2000) - } - } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 598a8e740772..1cd495dfee49 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -341,7 +341,7 @@ public void run(AccountManagerFuture future) { mUploaderBinder.cancel(accountName); } if (mDownloaderBinder != null) { - mDownloaderBinder.cancel(accountName); + mDownloaderBinder.cancelAllDownloadsForAccount(accountName); } } @@ -436,7 +436,7 @@ private void performAccountRemoval(User user) { mUploaderBinder.cancel(user); } if (mDownloaderBinder != null) { - mDownloaderBinder.cancel(user.getAccountName()); + mDownloaderBinder.cancelAllDownloadsForAccount(user.getAccountName()); } backgroundJobManager.startAccountRemovalJob(user.getAccountName(), false); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 6aa4af298815..9f16f82dd003 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -696,7 +696,7 @@ public void listenForTransferProgress() { if (progressListener != null) { if (containerActivity.getFileDownloaderBinder() != null) { containerActivity.getFileDownloaderBinder(). - addDatatransferProgressListener(progressListener, getFile()); + addDataTransferProgressListener(progressListener, getFile()); } if (containerActivity.getFileUploaderBinder() != null) { containerActivity.getFileUploaderBinder(). @@ -711,7 +711,7 @@ private void leaveTransferProgress() { if (progressListener != null) { if (containerActivity.getFileDownloaderBinder() != null) { containerActivity.getFileDownloaderBinder(). - removeDatatransferProgressListener(progressListener, getFile()); + removeDataTransferProgressListener(progressListener, getFile()); } if (containerActivity.getFileUploaderBinder() != null) { containerActivity.getFileUploaderBinder(). diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index a3e7411dc2bf..8700a80c61f1 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -999,7 +999,7 @@ public void cancelTransference(OCFile file) { // for both files and folders FilesDownloadWorker.FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder(); if (downloaderBinder != null && downloaderBinder.isDownloading(currentUser, file)) { - downloaderBinder.cancel(currentUser.toPlatformAccount(), file); + downloaderBinder.cancelPendingOrCurrentDownloads(currentUser.toPlatformAccount(), file); } FileUploaderBinder uploaderBinder = fileActivity.getFileUploaderBinder(); if (uploaderBinder != null && uploaderBinder.isUploading(currentUser, file)) { diff --git a/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java index 4aa7a19ba7c5..d7c05e595409 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java @@ -261,8 +261,8 @@ private void setButtonsForRemote() { public void listenForTransferProgress() { - if (mProgressListener != null && !mListening && containerActivity.getFileDownloadProgressListener() != null) { - containerActivity.getFileDownloadProgressListener().addDataTransferProgressListener(mProgressListener, getFile()); + if (mProgressListener != null && !mListening && containerActivity.getFileDownloaderBinder() != null) { + containerActivity.getFileDownloaderBinder().addDataTransferProgressListener(mProgressListener, getFile()); mListening = true; setButtonsForTransferring(); } @@ -270,8 +270,8 @@ public void listenForTransferProgress() { public void leaveTransferProgress() { - if (mProgressListener != null && containerActivity.getFileDownloadProgressListener() != null) { - containerActivity.getFileDownloadProgressListener() + if (mProgressListener != null && containerActivity.getFileDownloaderBinder() != null) { + containerActivity.getFileDownloaderBinder() .removeDataTransferProgressListener(mProgressListener, getFile()); mListening = false; } From 26804d1954f6a868bf0d5b7507af14ec30e3da0e Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 16:28:37 +0100 Subject: [PATCH 101/189] Use interfaceSerializer Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 12 +++- .../client/jobs/BackgroundJobManagerImpl.kt | 5 +- .../nextcloud/utils/InterfaceSerializer.java | 56 +++++++++++++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index 787bcb4f10ff..d81c61358b80 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -39,9 +39,12 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters import com.google.gson.Gson +import com.google.gson.GsonBuilder import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional +import com.nextcloud.utils.InterfaceSerializer +import com.nextcloud.utils.InterfaceSerializer.interfaceSerializer import com.owncloud.android.R import com.owncloud.android.authentication.AuthenticatorActivity import com.owncloud.android.datamodel.FileDataStorageManager @@ -85,7 +88,6 @@ class FilesDownloadWorker( companion object { private val TAG = FilesDownloadWorker::class.java.simpleName - var user: User? = null const val USER = "USER" const val FILE = "FILE" const val BEHAVIOUR = "BEHAVIOUR" @@ -144,9 +146,17 @@ class FilesDownloadWorker( } } + // FIXME stackoverflow + private fun getUserGson(): Gson { + return GsonBuilder() + .registerTypeAdapter(User::class.java, interfaceSerializer(User::class.java)) + .create() + } + private fun getRequestDownloads(): AbstractList { conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) + val user = getUserGson().fromJson(inputData.keyValueMap[USER] as String, User::class.java) val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? val downloadType = if (downloadTypeAsString != null) { if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 249542077afd..e1ea1a2957d4 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -520,9 +520,8 @@ internal class BackgroundJobManagerImpl( ) { val gson = Gson() - // FIXME user interface cant serialize and deserialize val data = workDataOf( - //FilesDownloadWorker.USER to gson.toJson(user), + FilesDownloadWorker.USER to gson.toJson(user), FilesDownloadWorker.FILE to gson.toJson(ocFile), FilesDownloadWorker.BEHAVIOUR to behaviour, FilesDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), @@ -531,8 +530,6 @@ internal class BackgroundJobManagerImpl( FilesDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId, ) - FilesDownloadWorker.user = user - val request = oneTimeRequestBuilder(FilesDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .setInputData(data) .build() diff --git a/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java b/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java new file mode 100644 index 000000000000..da253c14d9b5 --- /dev/null +++ b/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java @@ -0,0 +1,56 @@ +/* + * 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 . + */ + +package com.nextcloud.utils; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +import java.lang.reflect.Type; + +final public class InterfaceSerializer implements JsonSerializer, JsonDeserializer { + + private final Class implementationClass; + + private InterfaceSerializer(final Class implementationClass) { + this.implementationClass = implementationClass; + } + + public static InterfaceSerializer interfaceSerializer(final Class implementationClass) { + return new InterfaceSerializer<>(implementationClass); + } + + @Override + public JsonElement serialize(final T value, final Type type, final JsonSerializationContext context) { + final Type targetType = value != null + ? value.getClass() + : type; + return context.serialize(value, targetType); + } + + @Override + public T deserialize(final JsonElement jsonElement, final Type typeOfT, final JsonDeserializationContext context) { + return context.deserialize(jsonElement, implementationClass); + } +} From a12dca59e778d230b8130a00ec0afc5d872a7aa2 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 20 Dec 2023 09:13:15 +0100 Subject: [PATCH 102/189] Create user from accountName Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 15 +---- .../client/jobs/BackgroundJobManagerImpl.kt | 2 +- .../nextcloud/utils/InterfaceSerializer.java | 56 ------------------- 3 files changed, 4 insertions(+), 69 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index d81c61358b80..2b76379698fd 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -39,12 +39,9 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters import com.google.gson.Gson -import com.google.gson.GsonBuilder import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional -import com.nextcloud.utils.InterfaceSerializer -import com.nextcloud.utils.InterfaceSerializer.interfaceSerializer import com.owncloud.android.R import com.owncloud.android.authentication.AuthenticatorActivity import com.owncloud.android.datamodel.FileDataStorageManager @@ -88,7 +85,7 @@ class FilesDownloadWorker( companion object { private val TAG = FilesDownloadWorker::class.java.simpleName - const val USER = "USER" + const val USER_NAME = "USER" const val FILE = "FILE" const val BEHAVIOUR = "BEHAVIOUR" const val DOWNLOAD_TYPE = "DOWNLOAD_TYPE" @@ -146,17 +143,11 @@ class FilesDownloadWorker( } } - // FIXME stackoverflow - private fun getUserGson(): Gson { - return GsonBuilder() - .registerTypeAdapter(User::class.java, interfaceSerializer(User::class.java)) - .create() - } - private fun getRequestDownloads(): AbstractList { conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) - val user = getUserGson().fromJson(inputData.keyValueMap[USER] as String, User::class.java) + val accountName = inputData.keyValueMap[USER_NAME] as String + val user = accountManager.getUser(accountName).get() val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? val downloadType = if (downloadTypeAsString != null) { if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index e1ea1a2957d4..bad195010b08 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -521,7 +521,7 @@ internal class BackgroundJobManagerImpl( val gson = Gson() val data = workDataOf( - FilesDownloadWorker.USER to gson.toJson(user), + FilesDownloadWorker.USER_NAME to user.accountName, FilesDownloadWorker.FILE to gson.toJson(ocFile), FilesDownloadWorker.BEHAVIOUR to behaviour, FilesDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), diff --git a/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java b/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java deleted file mode 100644 index da253c14d9b5..000000000000 --- a/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java +++ /dev/null @@ -1,56 +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 . - */ - -package com.nextcloud.utils; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; - -import java.lang.reflect.Type; - -final public class InterfaceSerializer implements JsonSerializer, JsonDeserializer { - - private final Class implementationClass; - - private InterfaceSerializer(final Class implementationClass) { - this.implementationClass = implementationClass; - } - - public static InterfaceSerializer interfaceSerializer(final Class implementationClass) { - return new InterfaceSerializer<>(implementationClass); - } - - @Override - public JsonElement serialize(final T value, final Type type, final JsonSerializationContext context) { - final Type targetType = value != null - ? value.getClass() - : type; - return context.serialize(value, targetType); - } - - @Override - public T deserialize(final JsonElement jsonElement, final Type typeOfT, final JsonDeserializationContext context) { - return context.deserialize(jsonElement, implementationClass); - } -} From e4d738512400f4fd3b57f52a182cfec9c990a23d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 20 Dec 2023 09:46:36 +0100 Subject: [PATCH 103/189] Code cleanup Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 271 ++++++++++-------- 1 file changed, 149 insertions(+), 122 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index 2b76379698fd..fa0de11d9e74 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -132,6 +132,7 @@ class FilesDownloadWorker( val it: Iterator = requestDownloads.iterator() while (it.hasNext()) { val next = it.next() + Log_OC.e(TAG, "Download Key: $next") downloadFile(next) } @@ -175,7 +176,7 @@ class FilesDownloadWorker( ) operation.addDatatransferProgressListener(this) operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder?) - val putResult: Pair = pendingDownloads.putIfAbsent( + val putResult = pendingDownloads.putIfAbsent( user?.accountName, file.remotePath, operation @@ -235,18 +236,15 @@ class FilesDownloadWorker( } private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { - var downloadResult = result - val removeResult: Pair = pendingDownloads.removePayload( + val removeResult = pendingDownloads.removePayload( currentDownload?.user?.accountName, currentDownload?.remotePath ) - if (downloadResult == null) { - downloadResult = RemoteOperationResult(RuntimeException("Error downloading…")) - } + val downloadResult = result ?: RemoteOperationResult(RuntimeException("Error downloading…")) - currentDownload?.let { - notifyDownloadResult(it, downloadResult) - sendBroadcastDownloadFinished(it, downloadResult, removeResult.second) + currentDownload?.run { + notifyDownloadResult(this, downloadResult) + sendBroadcastDownloadFinished(this, downloadResult, removeResult.second) } } @@ -269,16 +267,25 @@ class FilesDownloadWorker( val file = getCurrentFile() ?: return val syncDate = System.currentTimeMillis() - file.lastSyncDateForProperties = syncDate - file.lastSyncDateForData = syncDate - file.isUpdateThumbnailNeeded = true - file.modificationTimestamp = currentDownload?.modificationTimestamp ?: 0L - file.modificationTimestampAtLastSyncForData = currentDownload?.modificationTimestamp ?: 0L - file.etag = currentDownload?.etag - file.mimeType = currentDownload?.mimeType - file.storagePath = currentDownload?.savePath - file.fileLength = File(currentDownload?.getSavePath()).length() - file.remoteId = currentDownload?.file?.remoteId + + file.apply { + lastSyncDateForProperties = syncDate + lastSyncDateForData = syncDate + isUpdateThumbnailNeeded = true + modificationTimestamp = currentDownload?.modificationTimestamp ?: 0L + modificationTimestampAtLastSyncForData = currentDownload?.modificationTimestamp ?: 0L + etag = currentDownload?.etag + mimeType = currentDownload?.mimeType + storagePath = currentDownload?.savePath + + val savePathFile = currentDownload?.savePath?.let { File(it) } + savePathFile?.let { + fileLength = savePathFile.length() + } + + remoteId = currentDownload?.file?.remoteId + } + storageManager?.saveFile(file) if (MimeTypeUtil.isMedia(currentDownload?.mimeType)) { @@ -293,18 +300,20 @@ class FilesDownloadWorker( downloadResult: RemoteOperationResult<*>, unlinkedFromRemotePath: String? ) { - val end = Intent(getDownloadFinishMessage()) - end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) - end.putExtra(ACCOUNT_NAME, download.user.accountName) - end.putExtra(EXTRA_REMOTE_PATH, download.remotePath) - end.putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) - end.putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) - end.putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) - if (unlinkedFromRemotePath != null) { - end.putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) - } - end.setPackage(context.packageName) - localBroadcastManager.sendBroadcast(end) + val intent = Intent(getDownloadFinishMessage()).apply { + putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) + putExtra(ACCOUNT_NAME, download.user.accountName) + putExtra(EXTRA_REMOTE_PATH, download.remotePath) + putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) + putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) + putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) + if (unlinkedFromRemotePath != null) { + putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) + } + setPackage(context.packageName) + } + + localBroadcastManager.sendBroadcast(intent) } private fun notifyDownloadResult( @@ -315,72 +324,71 @@ class FilesDownloadWorker( notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager } - if (!downloadResult.isCancelled) { - if (downloadResult.isSuccess) { - conflictUploadId?.let { - if (it > 0) { - uploadsStorageManager.removeUpload(it) - } - } + if (downloadResult.isCancelled) { + return + } - return - } - var tickerId = - if (downloadResult.isSuccess) R.string.downloader_download_succeeded_ticker else R.string.downloader_download_failed_ticker - val needsToUpdateCredentials = ResultCode.UNAUTHORIZED == downloadResult.code - tickerId = if (needsToUpdateCredentials) R.string.downloader_download_failed_credentials_error else tickerId - - notificationBuilder - ?.setTicker(context.getString(tickerId)) - ?.setContentTitle(context.getString(tickerId)) - ?.setAutoCancel(true) - ?.setOngoing(false) - ?.setProgress(0, 0, false) - - if (needsToUpdateCredentials) { - configureUpdateCredentialsNotification(download.user) - } else { - // TODO put something smart in showDetailsIntent - val showDetailsIntent = Intent() - notificationBuilder?.setContentIntent( - PendingIntent.getActivity( - context, System.currentTimeMillis().toInt(), - showDetailsIntent, PendingIntent.FLAG_IMMUTABLE - ) - ) + if (downloadResult.isSuccess) { + conflictUploadId?.let { + if (it > 0) { + uploadsStorageManager.removeUpload(it) + } } - notificationBuilder?.setContentText( - ErrorMessageAdapter.getErrorCauseMessage( - downloadResult, - download, context.resources - ) + return + } + + var tickerId = + if (downloadResult.isSuccess) R.string.downloader_download_succeeded_ticker else R.string.downloader_download_failed_ticker + val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) + tickerId = if (needsToUpdateCredentials) R.string.downloader_download_failed_credentials_error else tickerId + + notificationBuilder + ?.setTicker(context.getString(tickerId)) + ?.setContentTitle(context.getString(tickerId)) + ?.setAutoCancel(true) + ?.setOngoing(false) + ?.setProgress(0, 0, false) + + if (needsToUpdateCredentials) { + configureUpdateCredentialsNotification(download.user) + } else { + showDetailsIntent(null) + } + + notificationBuilder?.setContentText( + ErrorMessageAdapter.getErrorCauseMessage( + downloadResult, + download, context.resources ) + ) - notificationManager?.notify(SecureRandom().nextInt(), notificationBuilder?.build()) - if (downloadResult.isSuccess) { - NotificationUtils.cancelWithDelay( - notificationManager, - R.string.downloader_download_succeeded_ticker, 2000 - ) - } + notificationManager?.notify(SecureRandom().nextInt(), notificationBuilder?.build()) + + if (downloadResult.isSuccess) { + NotificationUtils.cancelWithDelay( + notificationManager, + R.string.downloader_download_succeeded_ticker, 2000 + ) } } private fun configureUpdateCredentialsNotification(user: User) { - val updateAccountCredentials = Intent(context, AuthenticatorActivity::class.java) - updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) - updateAccountCredentials.putExtra( - AuthenticatorActivity.EXTRA_ACTION, - AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN - ) - updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) - updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND) + val intent = Intent(context, AuthenticatorActivity::class.java).apply { + putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) + putExtra( + AuthenticatorActivity.EXTRA_ACTION, + AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN + ) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + addFlags(Intent.FLAG_FROM_BACKGROUND) + } + notificationBuilder?.setContentIntent( PendingIntent.getActivity( context, System.currentTimeMillis().toInt(), - updateAccountCredentials, + intent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE ) ) @@ -400,32 +408,38 @@ class FilesDownloadWorker( File(download.savePath).name ) ) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { notificationBuilder?.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) } - /// includes a pending intent in the notification showing the details view of the file - var showDetailsIntent: Intent? = null - showDetailsIntent = if (PreviewImageFragment.canBePreviewed(download.file)) { - Intent(context, PreviewImageActivity::class.java) + showDetailsIntent(download) + notifyDownloadInProgressNotification() + } + + private fun showDetailsIntent(operation: DownloadFileOperation?) { + val intent: Intent = if (operation != null) { + if (PreviewImageFragment.canBePreviewed(operation.file)) { + Intent(context, PreviewImageActivity::class.java) + } else { + Intent(context, FileDisplayActivity::class.java) + }.apply { + putExtra(FileActivity.EXTRA_FILE, operation.file) + putExtra(FileActivity.EXTRA_USER, operation.user) + flags = Intent.FLAG_ACTIVITY_CLEAR_TOP + } } else { - Intent(context, FileDisplayActivity::class.java) + Intent() } - showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, download.file) - showDetailsIntent.putExtra(FileActivity.EXTRA_USER, download.user) - showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + notificationBuilder?.setContentIntent( PendingIntent.getActivity( - context, System.currentTimeMillis().toInt(), - showDetailsIntent, PendingIntent.FLAG_IMMUTABLE + context, + System.currentTimeMillis().toInt(), + intent, + PendingIntent.FLAG_IMMUTABLE ) ) - - if (notificationManager == null) { - notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - } - - notificationManager?.notify(R.string.downloader_download_in_progress_ticker, notificationBuilder?.build()) } private fun showDownloadingFilesNotification() { @@ -435,7 +449,6 @@ class FilesDownloadWorker( .setSmallIcon(R.drawable.notification_icon) .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { builder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) } @@ -456,12 +469,14 @@ class FilesDownloadWorker( download: DownloadFileOperation, linkedToRemotePath: String ) { - val added = Intent(getDownloadAddedMessage()) - added.putExtra(ACCOUNT_NAME, download.user.accountName) - added.putExtra(EXTRA_REMOTE_PATH, download.remotePath) - added.putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath) - added.setPackage(context.packageName) - localBroadcastManager.sendBroadcast(added) + val intent = Intent(getDownloadAddedMessage()).apply { + putExtra(ACCOUNT_NAME, download.user.accountName) + putExtra(EXTRA_REMOTE_PATH, download.remotePath) + putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath) + setPackage(context.packageName) + } + + localBroadcastManager.sendBroadcast(intent) } override fun onAccountsUpdated(accounts: Array?) { @@ -477,6 +492,7 @@ class FilesDownloadWorker( filePath: String ) { val percent: Int = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt() + if (percent != lastPercent) { notificationBuilder?.setProgress(100, percent, totalToTransfer < 0) val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) @@ -484,17 +500,22 @@ class FilesDownloadWorker( String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) notificationBuilder?.setContentText(text) - if (notificationManager == null) { - notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - } - notificationManager?.notify( - R.string.downloader_download_in_progress_ticker, - notificationBuilder?.build() - ) + notifyDownloadInProgressNotification() } + lastPercent = percent } + private fun notifyDownloadInProgressNotification() { + if (notificationManager == null) { + notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + } + notificationManager?.notify( + R.string.downloader_download_in_progress_ticker, + notificationBuilder?.build() + ) + } + inner class FileDownloaderBinder : Binder(), OnDatatransferProgressListener { private val boundListeners: MutableMap = HashMap() @@ -502,11 +523,13 @@ class FilesDownloadWorker( val removeResult: Pair = pendingDownloads.remove(account.name, file.remotePath) val download = removeResult.first + if (download != null) { download.cancel() } else { - if (currentDownload != null && currentUser?.isPresent == true && - currentDownload?.remotePath?.startsWith(file.remotePath) == true && account.name == currentUser.get()?.accountName + if (currentUser?.isPresent == true && + currentDownload?.remotePath?.startsWith(file.remotePath) == true && + account.name == currentUser.get()?.accountName ) { currentDownload?.cancel() } @@ -514,7 +537,7 @@ class FilesDownloadWorker( } fun cancelAllDownloadsForAccount(accountName: String?) { - if (currentDownload != null && currentDownload?.user?.nameEquals(accountName) == true) { + if (currentDownload?.user?.nameEquals(accountName) == true) { currentDownload?.cancel() } @@ -529,6 +552,7 @@ class FilesDownloadWorker( if (file == null || listener == null) { return } + boundListeners[file.fileId] = listener } @@ -536,6 +560,7 @@ class FilesDownloadWorker( if (file == null || listener == null) { return } + val fileId = file.fileId if (boundListeners[fileId] === listener) { boundListeners.remove(fileId) @@ -543,11 +568,13 @@ class FilesDownloadWorker( } override fun onTransferProgress( - progressRate: Long, totalTransferredSoFar: Long, - totalToTransfer: Long, fileName: String + progressRate: Long, + totalTransferredSoFar: Long, + totalToTransfer: Long, + fileName: String ) { - val boundListener = boundListeners[currentDownload?.file?.fileId] - boundListener?.onTransferProgress( + val listener = boundListeners[currentDownload?.file?.fileId] + listener?.onTransferProgress( progressRate, totalTransferredSoFar, totalToTransfer, fileName ) From 5559d7bf66fdd92007238e57897f02672d1f3078 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 20 Dec 2023 10:19:09 +0100 Subject: [PATCH 104/189] Code cleanup Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadWorker.kt | 266 ++++++++++-------- 1 file changed, 143 insertions(+), 123 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index fa0de11d9e74..bb46aa399ddc 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -112,8 +112,8 @@ class FilesDownloadWorker( private var currentDownload: DownloadFileOperation? = null private var conflictUploadId: Long? = null private var lastPercent = 0 - private var notificationBuilder: NotificationCompat.Builder? = null - private var notificationManager: NotificationManager? = null + private lateinit var notificationBuilder: NotificationCompat.Builder + private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager private val pendingDownloads = IndexedForest() private var downloadBinder: IBinder? = null private var currentUser = Optional.empty() @@ -126,15 +126,9 @@ class FilesDownloadWorker( return try { val requestDownloads = getRequestDownloads() - showDownloadingFilesNotification() + initNotificationBuilder() addAccountUpdateListener() - - val it: Iterator = requestDownloads.iterator() - while (it.hasNext()) { - val next = it.next() - Log_OC.e(TAG, "Download Key: $next") - downloadFile(next) - } + startDownloadForEachRequest(requestDownloads) Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() @@ -191,6 +185,35 @@ class FilesDownloadWorker( return requestedDownloads } + + private fun initNotificationBuilder() { + notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) + .setContentTitle(context.resources.getString(R.string.app_name)) + .setContentText(context.resources.getString(R.string.foreground_service_download)) + .setSmallIcon(R.drawable.notification_icon) + .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + } + + notification = notificationBuilder.build() + } + + private fun addAccountUpdateListener() { + val am = AccountManager.get(context) + am.addOnAccountsUpdatedListener(this, null, false) + } + + private fun startDownloadForEachRequest(requestDownloads: AbstractList) { + val it: Iterator = requestDownloads.iterator() + while (it.hasNext()) { + val next = it.next() + Log_OC.e(TAG, "Download Key: $next") + + downloadFile(next) + } + } private fun downloadFile(downloadKey: String) { startedDownload = true @@ -225,42 +248,31 @@ class FilesDownloadWorker( } } - private fun getOCAccountForDownload(): OwnCloudAccount { - val currentDownloadAccount = currentDownload?.user?.toPlatformAccount() - val currentDownloadUser = accountManager.getUser(currentDownloadAccount?.name) - if (currentUser != currentDownloadUser) { - currentUser = currentDownloadUser - storageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) - } - return currentDownloadUser.get().toOwnCloudAccount() + private fun cancelPendingDownloads(accountName: String?) { + pendingDownloads.remove(accountName) } - private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { - val removeResult = pendingDownloads.removePayload( - currentDownload?.user?.accountName, currentDownload?.remotePath - ) + private fun notifyDownloadStart(download: DownloadFileOperation) { + lastPercent = 0 - val downloadResult = result ?: RemoteOperationResult(RuntimeException("Error downloading…")) + configureNotificationBuilderForDownloadStart(download) - currentDownload?.run { - notifyDownloadResult(this, downloadResult) - sendBroadcastDownloadFinished(this, downloadResult, removeResult.second) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) } - } - - private fun getCurrentFile(): OCFile? { - var file: OCFile? = currentDownload?.file?.fileId?.let { storageManager?.getFileById(it) } - if (file == null) { - file = storageManager?.getFileByDecryptedRemotePath(currentDownload?.file?.remotePath) - } + showDetailsIntent(download) + notifyDownloadInProgressNotification() + } - if (file == null) { - Log_OC.e(this, "Could not save " + currentDownload?.file?.remotePath) - return null + private fun getOCAccountForDownload(): OwnCloudAccount { + val currentDownloadAccount = currentDownload?.user?.toPlatformAccount() + val currentDownloadUser = accountManager.getUser(currentDownloadAccount?.name) + if (currentUser != currentDownloadUser) { + currentUser = currentDownloadUser + storageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) } - - return file + return currentDownloadUser.get().toOwnCloudAccount() } private fun saveDownloadedFile() { @@ -295,60 +307,49 @@ class FilesDownloadWorker( storageManager?.saveConflict(file, null) } - private fun sendBroadcastDownloadFinished( - download: DownloadFileOperation, - downloadResult: RemoteOperationResult<*>, - unlinkedFromRemotePath: String? - ) { - val intent = Intent(getDownloadFinishMessage()).apply { - putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) - putExtra(ACCOUNT_NAME, download.user.accountName) - putExtra(EXTRA_REMOTE_PATH, download.remotePath) - putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) - putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) - putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) - if (unlinkedFromRemotePath != null) { - putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) - } - setPackage(context.packageName) + private fun getCurrentFile(): OCFile? { + var file: OCFile? = currentDownload?.file?.fileId?.let { storageManager?.getFileById(it) } + + if (file == null) { + file = storageManager?.getFileByDecryptedRemotePath(currentDownload?.file?.remotePath) } - localBroadcastManager.sendBroadcast(intent) + if (file == null) { + Log_OC.e(this, "Could not save " + currentDownload?.file?.remotePath) + return null + } + + return file + } + + private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { + val removeResult = pendingDownloads.removePayload( + currentDownload?.user?.accountName, currentDownload?.remotePath + ) + + val downloadResult = result ?: RemoteOperationResult(RuntimeException("Error downloading…")) + + currentDownload?.run { + notifyDownloadResult(this, downloadResult) + sendBroadcastDownloadFinished(this, downloadResult, removeResult.second) + } } private fun notifyDownloadResult( download: DownloadFileOperation, downloadResult: RemoteOperationResult<*> ) { - if (notificationManager == null) { - notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - } - if (downloadResult.isCancelled) { return } if (downloadResult.isSuccess) { - conflictUploadId?.let { - if (it > 0) { - uploadsStorageManager.removeUpload(it) - } - } - + dismissDownloadInProgressNotification() return } - var tickerId = - if (downloadResult.isSuccess) R.string.downloader_download_succeeded_ticker else R.string.downloader_download_failed_ticker val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) - tickerId = if (needsToUpdateCredentials) R.string.downloader_download_failed_credentials_error else tickerId - - notificationBuilder - ?.setTicker(context.getString(tickerId)) - ?.setContentTitle(context.getString(tickerId)) - ?.setAutoCancel(true) - ?.setOngoing(false) - ?.setProgress(0, 0, false) + configureNotificationBuilderForDownloadResult(downloadResult, needsToUpdateCredentials) if (needsToUpdateCredentials) { configureUpdateCredentialsNotification(download.user) @@ -356,23 +357,76 @@ class FilesDownloadWorker( showDetailsIntent(null) } - notificationBuilder?.setContentText( - ErrorMessageAdapter.getErrorCauseMessage( - downloadResult, - download, context.resources - ) + notifyNotificationBuilderForDownloadResult(downloadResult, download) + } + + private fun configureNotificationBuilderForDownloadResult( + downloadResult: RemoteOperationResult<*>, + needsToUpdateCredentials: Boolean + ) { + var tickerId = + if (downloadResult.isSuccess) R.string.downloader_download_succeeded_ticker else R.string.downloader_download_failed_ticker + tickerId = if (needsToUpdateCredentials) R.string.downloader_download_failed_credentials_error else tickerId + + notificationBuilder + .setTicker(context.getString(tickerId)) + .setContentTitle(context.getString(tickerId)) + .setAutoCancel(true) + .setOngoing(false) + .setProgress(0, 0, false) + } + + private fun notifyNotificationBuilderForDownloadResult(downloadResult: RemoteOperationResult<*>, download: DownloadFileOperation) { + val errorMessage = ErrorMessageAdapter.getErrorCauseMessage( + downloadResult, + download, + context.resources ) - notificationManager?.notify(SecureRandom().nextInt(), notificationBuilder?.build()) + notificationBuilder.setContentText(errorMessage) + + notificationManager.notify(SecureRandom().nextInt(), notificationBuilder.build()) if (downloadResult.isSuccess) { NotificationUtils.cancelWithDelay( notificationManager, - R.string.downloader_download_succeeded_ticker, 2000 + R.string.downloader_download_succeeded_ticker, + 2000 ) } } + private fun sendBroadcastDownloadFinished( + download: DownloadFileOperation, + downloadResult: RemoteOperationResult<*>, + unlinkedFromRemotePath: String? + ) { + val intent = Intent(getDownloadFinishMessage()).apply { + putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) + putExtra(ACCOUNT_NAME, download.user.accountName) + putExtra(EXTRA_REMOTE_PATH, download.remotePath) + putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) + putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) + putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) + if (unlinkedFromRemotePath != null) { + putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) + } + setPackage(context.packageName) + } + + localBroadcastManager.sendBroadcast(intent) + } + + private fun dismissDownloadInProgressNotification() { + conflictUploadId?.let { + if (it > 0) { + uploadsStorageManager.removeUpload(it) + } + } + + notificationManager.cancel(R.string.downloader_download_in_progress_ticker) + } + private fun configureUpdateCredentialsNotification(user: User) { val intent = Intent(context, AuthenticatorActivity::class.java).apply { putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) @@ -385,7 +439,7 @@ class FilesDownloadWorker( addFlags(Intent.FLAG_FROM_BACKGROUND) } - notificationBuilder?.setContentIntent( + notificationBuilder.setContentIntent( PendingIntent.getActivity( context, System.currentTimeMillis().toInt(), intent, @@ -394,8 +448,7 @@ class FilesDownloadWorker( ) } - private fun notifyDownloadStart(download: DownloadFileOperation) { - lastPercent = 0 + private fun configureNotificationBuilderForDownloadStart(download: DownloadFileOperation) { notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) .setSmallIcon(R.drawable.notification_icon) .setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) @@ -408,13 +461,6 @@ class FilesDownloadWorker( File(download.savePath).name ) ) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - notificationBuilder?.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) - } - - showDetailsIntent(download) - notifyDownloadInProgressNotification() } private fun showDetailsIntent(operation: DownloadFileOperation?) { @@ -432,7 +478,7 @@ class FilesDownloadWorker( Intent() } - notificationBuilder?.setContentIntent( + notificationBuilder.setContentIntent( PendingIntent.getActivity( context, System.currentTimeMillis().toInt(), @@ -442,29 +488,6 @@ class FilesDownloadWorker( ) } - private fun showDownloadingFilesNotification() { - val builder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) - .setContentTitle(context.resources.getString(R.string.app_name)) - .setContentText(context.resources.getString(R.string.foreground_service_download)) - .setSmallIcon(R.drawable.notification_icon) - .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - builder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) - } - - notification = builder.build() - } - - private fun addAccountUpdateListener() { - val am = AccountManager.get(context) - am.addOnAccountsUpdatedListener(this, null, false) - } - - private fun cancelPendingDownloads(accountName: String?) { - pendingDownloads.remove(accountName) - } - private fun sendBroadcastNewDownload( download: DownloadFileOperation, linkedToRemotePath: String @@ -494,11 +517,11 @@ class FilesDownloadWorker( val percent: Int = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt() if (percent != lastPercent) { - notificationBuilder?.setProgress(100, percent, totalToTransfer < 0) + notificationBuilder.setProgress(100, percent, totalToTransfer < 0) val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) val text = String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) - notificationBuilder?.setContentText(text) + notificationBuilder.setContentText(text) notifyDownloadInProgressNotification() } @@ -507,12 +530,9 @@ class FilesDownloadWorker( } private fun notifyDownloadInProgressNotification() { - if (notificationManager == null) { - notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - } - notificationManager?.notify( + notificationManager.notify( R.string.downloader_download_in_progress_ticker, - notificationBuilder?.build() + notificationBuilder.build() ) } From 9226a14dda42916fe88ca2a0b12353a03e51bbc8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 20 Dec 2023 11:33:29 +0100 Subject: [PATCH 105/189] Fix download progress Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadHelper.kt | 6 +++--- .../files/downloader/FilesDownloadWorker.kt | 18 ++++++++++++------ .../android/ui/activity/ComponentsGetter.java | 2 +- .../ui/activity/FileDisplayActivity.java | 3 ++- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt index 8a0a855f84b5..94803b9b297c 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt @@ -46,7 +46,7 @@ class FilesDownloadHelper { user, ocFile, "", - null, + DownloadType.DOWNLOAD, "", "", null @@ -58,7 +58,7 @@ class FilesDownloadHelper { user, ocFile, behaviour, - null, + DownloadType.DOWNLOAD, "", "", null @@ -82,7 +82,7 @@ class FilesDownloadHelper { user, ocFile, "", - null, + DownloadType.DOWNLOAD, "", "", conflictUploadId diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index bb46aa399ddc..b9bd074c64ef 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -115,7 +115,7 @@ class FilesDownloadWorker( private lateinit var notificationBuilder: NotificationCompat.Builder private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager private val pendingDownloads = IndexedForest() - private var downloadBinder: IBinder? = null + private var downloadBinder: IBinder = FileDownloaderBinder() private var currentUser = Optional.empty() private var startedDownload = false private var storageManager: FileDataStorageManager? = null @@ -158,6 +158,7 @@ class FilesDownloadWorker( val packageName = inputData.keyValueMap[PACKAGE_NAME] as String val requestedDownloads: AbstractList = Vector() + try { val operation = DownloadFileOperation( user, @@ -169,16 +170,19 @@ class FilesDownloadWorker( downloadType ) operation.addDatatransferProgressListener(this) - operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder?) + operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder) val putResult = pendingDownloads.putIfAbsent( user?.accountName, file.remotePath, operation ) - val downloadKey = putResult.first - requestedDownloads.add(downloadKey) - sendBroadcastNewDownload(operation, putResult.second) + if (putResult != null) { + val downloadKey = putResult.first + requestedDownloads.add(downloadKey) + sendBroadcastNewDownload(operation, putResult.second) + } + } catch (e: IllegalArgumentException) { Log_OC.e(TAG, "Not enough information provided in intent: " + e.message) } @@ -207,12 +211,14 @@ class FilesDownloadWorker( private fun startDownloadForEachRequest(requestDownloads: AbstractList) { val it: Iterator = requestDownloads.iterator() + while (it.hasNext()) { val next = it.next() Log_OC.e(TAG, "Download Key: $next") - downloadFile(next) } + + startedDownload = false } private fun downloadFile(downloadKey: String) { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java index 4b0ab8c6de2e..9ae88f3c7248 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java @@ -30,7 +30,7 @@ public interface ComponentsGetter { /** * To be invoked when the parent activity is fully created to get a reference - * to the FileDownloader service API. + * to the FileDownloadWorker. */ public FilesDownloadWorker.FileDownloaderBinder getFileDownloaderBinder(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 106dac2e027e..7e110b45a2c9 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -94,6 +94,7 @@ import com.owncloud.android.lib.resources.files.SearchRemoteOperation; import com.owncloud.android.operations.CopyFileOperation; import com.owncloud.android.operations.CreateFolderOperation; +import com.owncloud.android.operations.DownloadType; import com.owncloud.android.operations.MoveFileOperation; import com.owncloud.android.operations.RefreshFolderOperation; import com.owncloud.android.operations.RemoveFileOperation; @@ -1957,7 +1958,7 @@ public void run() { private void requestForDownload(OCFile file, String downloadBehaviour, String packageName, String activityName) { final User currentUser = getUser().orElseThrow(RuntimeException::new); if (!mDownloaderBinder.isDownloading(currentUser, mWaitingToPreview)) { - new FilesDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, null, activityName, packageName, null); + new FilesDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); } } From dbe9c58737073f8ce9ab6d21358505442bada4bb Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 20 Dec 2023 12:46:36 +0100 Subject: [PATCH 106/189] Cleanup code Signed-off-by: alperozturk --- .../files/downloader/FilesDownloadHelper.kt | 39 +++ .../files/downloader/FilesDownloadIntents.kt | 83 ++++++ .../files/downloader/FilesDownloadWorker.kt | 273 +++--------------- .../client/jobs/BackgroundJobManager.kt | 1 + .../client/jobs/BackgroundJobManagerImpl.kt | 2 +- .../download/DownloadNotificationManager.kt | 175 +++++++++++ 6 files changed, 335 insertions(+), 238 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt create mode 100644 app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt index 94803b9b297c..328d4b4b164d 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt @@ -24,9 +24,13 @@ package com.nextcloud.client.files.downloader import com.nextcloud.client.account.User import com.nextcloud.client.jobs.BackgroundJobManager import com.owncloud.android.MainApp +import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager +import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType +import com.owncloud.android.utils.MimeTypeUtil +import java.io.File import javax.inject.Inject class FilesDownloadHelper { @@ -41,6 +45,40 @@ class FilesDownloadHelper { MainApp.getAppComponent().inject(this) } + fun saveFile( + file: OCFile, + currentDownload: DownloadFileOperation?, + storageManager: FileDataStorageManager? + ) { + val syncDate = System.currentTimeMillis() + + file.apply { + lastSyncDateForProperties = syncDate + lastSyncDateForData = syncDate + isUpdateThumbnailNeeded = true + modificationTimestamp = currentDownload?.modificationTimestamp ?: 0L + modificationTimestampAtLastSyncForData = currentDownload?.modificationTimestamp ?: 0L + etag = currentDownload?.etag + mimeType = currentDownload?.mimeType + storagePath = currentDownload?.savePath + + val savePathFile = currentDownload?.savePath?.let { File(it) } + savePathFile?.let { + fileLength = savePathFile.length() + } + + remoteId = currentDownload?.file?.remoteId + } + + storageManager?.saveFile(file) + + if (MimeTypeUtil.isMedia(currentDownload?.mimeType)) { + FileDataStorageManager.triggerMediaScan(file.storagePath, file) + } + + storageManager?.saveConflict(file, null) + } + fun downloadFile(user: User, ocFile: OCFile) { backgroundJobManager.startFilesDownloadJob( user, @@ -89,6 +127,7 @@ class FilesDownloadHelper { ) } + @Suppress("LongParameterList") fun downloadFile( user: User, ocFile: OCFile, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt new file mode 100644 index 000000000000..d8d6e67a2c8f --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt @@ -0,0 +1,83 @@ +/* + * 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 . + */ + +package com.nextcloud.client.files.downloader + +import android.content.Context +import android.content.Intent +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.operations.DownloadFileOperation +import com.owncloud.android.ui.activity.FileActivity +import com.owncloud.android.ui.activity.FileDisplayActivity +import com.owncloud.android.ui.dialog.SendShareDialog +import com.owncloud.android.ui.fragment.OCFileListFragment +import com.owncloud.android.ui.preview.PreviewImageActivity +import com.owncloud.android.ui.preview.PreviewImageFragment + +class FilesDownloadIntents(private val context: Context) { + + fun newDownloadIntent( + download: DownloadFileOperation, + linkedToRemotePath: String + ): Intent { + return Intent(FilesDownloadWorker.getDownloadAddedMessage()).apply { + putExtra(FilesDownloadWorker.ACCOUNT_NAME, download.user.accountName) + putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) + putExtra(FilesDownloadWorker.EXTRA_LINKED_TO_PATH, linkedToRemotePath) + setPackage(context.packageName) + } + } + + fun downloadFinishedIntent( + download: DownloadFileOperation, + downloadResult: RemoteOperationResult<*>, + unlinkedFromRemotePath: String? + ): Intent { + return Intent(FilesDownloadWorker.getDownloadFinishMessage()).apply { + putExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) + putExtra(FilesDownloadWorker.ACCOUNT_NAME, download.user.accountName) + putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) + putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) + putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) + putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) + if (unlinkedFromRemotePath != null) { + putExtra(FilesDownloadWorker.EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) + } + setPackage(context.packageName) + } + } + + fun detailsIntent(operation: DownloadFileOperation?): Intent { + return if (operation != null) { + if (PreviewImageFragment.canBePreviewed(operation.file)) { + Intent(context, PreviewImageActivity::class.java) + } else { + Intent(context, FileDisplayActivity::class.java) + }.apply { + putExtra(FileActivity.EXTRA_FILE, operation.file) + putExtra(FileActivity.EXTRA_USER, operation.user) + flags = Intent.FLAG_ACTIVITY_CLEAR_TOP + } + } else { + Intent() + } + } +} diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt index b9bd074c64ef..79bd327cc50a 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt @@ -24,26 +24,19 @@ package com.nextcloud.client.files.downloader import android.accounts.Account import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener -import android.app.Notification -import android.app.NotificationManager import android.app.PendingIntent import android.content.Context -import android.content.Intent -import android.graphics.BitmapFactory import android.os.Binder -import android.os.Build import android.os.IBinder import android.util.Pair -import androidx.core.app.NotificationCompat import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters import com.google.gson.Gson import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional -import com.owncloud.android.R -import com.owncloud.android.authentication.AuthenticatorActivity import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager @@ -55,31 +48,20 @@ import com.owncloud.android.lib.common.network.OnDatatransferProgressListener import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode import com.owncloud.android.lib.common.utils.Log_OC -import com.owncloud.android.lib.resources.files.FileUtils import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType -import com.owncloud.android.ui.activity.FileActivity -import com.owncloud.android.ui.activity.FileDisplayActivity -import com.owncloud.android.ui.dialog.SendShareDialog -import com.owncloud.android.ui.fragment.OCFileListFragment -import com.owncloud.android.ui.notifications.NotificationUtils -import com.owncloud.android.ui.preview.PreviewImageActivity -import com.owncloud.android.ui.preview.PreviewImageFragment -import com.owncloud.android.utils.ErrorMessageAdapter -import com.owncloud.android.utils.MimeTypeUtil import com.owncloud.android.utils.theme.ViewThemeUtils -import java.io.File -import java.security.SecureRandom import java.util.AbstractList import java.util.Vector +@Suppress("LongParameterList") class FilesDownloadWorker( private val viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, private val uploadsStorageManager: UploadsStorageManager, private var localBroadcastManager: LocalBroadcastManager, private val context: Context, - params: WorkerParameters, + params: WorkerParameters ) : Worker(context, params), OnAccountsUpdateListener, OnDatatransferProgressListener { companion object { @@ -108,25 +90,26 @@ class FilesDownloadWorker( } } - private var notification: Notification? = null private var currentDownload: DownloadFileOperation? = null private var conflictUploadId: Long? = null private var lastPercent = 0 - private lateinit var notificationBuilder: NotificationCompat.Builder - private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + private val intents = FilesDownloadIntents(context) + private val notificationManager = DownloadNotificationManager(context, viewThemeUtils) private val pendingDownloads = IndexedForest() private var downloadBinder: IBinder = FileDownloaderBinder() private var currentUser = Optional.empty() + private val helper = FilesDownloadHelper() private var startedDownload = false private var storageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null private val gson = Gson() + @Suppress("TooGenericExceptionCaught") override fun doWork(): Result { return try { val requestDownloads = getRequestDownloads() - initNotificationBuilder() + notificationManager.init() addAccountUpdateListener() startDownloadForEachRequest(requestDownloads) @@ -180,29 +163,14 @@ class FilesDownloadWorker( if (putResult != null) { val downloadKey = putResult.first requestedDownloads.add(downloadKey) - sendBroadcastNewDownload(operation, putResult.second) + localBroadcastManager.sendBroadcast(intents.newDownloadIntent(operation, putResult.second)) } - } catch (e: IllegalArgumentException) { Log_OC.e(TAG, "Not enough information provided in intent: " + e.message) } return requestedDownloads } - - private fun initNotificationBuilder() { - notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) - .setContentTitle(context.resources.getString(R.string.app_name)) - .setContentText(context.resources.getString(R.string.foreground_service_download)) - .setSmallIcon(R.drawable.notification_icon) - .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) - } - - notification = notificationBuilder.build() - } private fun addAccountUpdateListener() { val am = AccountManager.get(context) @@ -221,6 +189,7 @@ class FilesDownloadWorker( startedDownload = false } + @Suppress("TooGenericExceptionCaught") private fun downloadFile(downloadKey: String) { startedDownload = true currentDownload = pendingDownloads.get(downloadKey) @@ -244,7 +213,9 @@ class FilesDownloadWorker( downloadResult = currentDownload?.execute(downloadClient) if (downloadResult?.isSuccess == true && currentDownload?.downloadType === DownloadType.DOWNLOAD) { - saveDownloadedFile() + getCurrentFile()?.let { + helper.saveFile(it, currentDownload, storageManager) + } } } catch (e: Exception) { Log_OC.e(TAG, "Error downloading", e) @@ -261,14 +232,9 @@ class FilesDownloadWorker( private fun notifyDownloadStart(download: DownloadFileOperation) { lastPercent = 0 - configureNotificationBuilderForDownloadStart(download) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) - } - - showDetailsIntent(download) - notifyDownloadInProgressNotification() + notificationManager.notifyForStart(download) + notificationManager.setContentIntent(intents.detailsIntent(download), PendingIntent.FLAG_IMMUTABLE) + notificationManager.showDownloadInProgressNotification() } private fun getOCAccountForDownload(): OwnCloudAccount { @@ -281,38 +247,6 @@ class FilesDownloadWorker( return currentDownloadUser.get().toOwnCloudAccount() } - private fun saveDownloadedFile() { - val file = getCurrentFile() ?: return - - val syncDate = System.currentTimeMillis() - - file.apply { - lastSyncDateForProperties = syncDate - lastSyncDateForData = syncDate - isUpdateThumbnailNeeded = true - modificationTimestamp = currentDownload?.modificationTimestamp ?: 0L - modificationTimestampAtLastSyncForData = currentDownload?.modificationTimestamp ?: 0L - etag = currentDownload?.etag - mimeType = currentDownload?.mimeType - storagePath = currentDownload?.savePath - - val savePathFile = currentDownload?.savePath?.let { File(it) } - savePathFile?.let { - fileLength = savePathFile.length() - } - - remoteId = currentDownload?.file?.remoteId - } - - storageManager?.saveFile(file) - - if (MimeTypeUtil.isMedia(currentDownload?.mimeType)) { - FileDataStorageManager.triggerMediaScan(file.storagePath, file) - } - - storageManager?.saveConflict(file, null) - } - private fun getCurrentFile(): OCFile? { var file: OCFile? = currentDownload?.file?.fileId?.let { storageManager?.getFileById(it) } @@ -330,14 +264,20 @@ class FilesDownloadWorker( private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { val removeResult = pendingDownloads.removePayload( - currentDownload?.user?.accountName, currentDownload?.remotePath + currentDownload?.user?.accountName, + currentDownload?.remotePath ) val downloadResult = result ?: RemoteOperationResult(RuntimeException("Error downloading…")) currentDownload?.run { notifyDownloadResult(this, downloadResult) - sendBroadcastDownloadFinished(this, downloadResult, removeResult.second) + val downloadFinishedIntent = intents.downloadFinishedIntent( + this, + downloadResult, + removeResult.second + ) + localBroadcastManager.sendBroadcast(downloadFinishedIntent) } } @@ -355,72 +295,15 @@ class FilesDownloadWorker( } val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) - configureNotificationBuilderForDownloadResult(downloadResult, needsToUpdateCredentials) + notificationManager.prepareForResult(downloadResult, needsToUpdateCredentials) if (needsToUpdateCredentials) { - configureUpdateCredentialsNotification(download.user) + notificationManager.setCredentialContentIntent(download.user) } else { - showDetailsIntent(null) - } - - notifyNotificationBuilderForDownloadResult(downloadResult, download) - } - - private fun configureNotificationBuilderForDownloadResult( - downloadResult: RemoteOperationResult<*>, - needsToUpdateCredentials: Boolean - ) { - var tickerId = - if (downloadResult.isSuccess) R.string.downloader_download_succeeded_ticker else R.string.downloader_download_failed_ticker - tickerId = if (needsToUpdateCredentials) R.string.downloader_download_failed_credentials_error else tickerId - - notificationBuilder - .setTicker(context.getString(tickerId)) - .setContentTitle(context.getString(tickerId)) - .setAutoCancel(true) - .setOngoing(false) - .setProgress(0, 0, false) - } - - private fun notifyNotificationBuilderForDownloadResult(downloadResult: RemoteOperationResult<*>, download: DownloadFileOperation) { - val errorMessage = ErrorMessageAdapter.getErrorCauseMessage( - downloadResult, - download, - context.resources - ) - - notificationBuilder.setContentText(errorMessage) - - notificationManager.notify(SecureRandom().nextInt(), notificationBuilder.build()) - - if (downloadResult.isSuccess) { - NotificationUtils.cancelWithDelay( - notificationManager, - R.string.downloader_download_succeeded_ticker, - 2000 - ) - } - } - - private fun sendBroadcastDownloadFinished( - download: DownloadFileOperation, - downloadResult: RemoteOperationResult<*>, - unlinkedFromRemotePath: String? - ) { - val intent = Intent(getDownloadFinishMessage()).apply { - putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) - putExtra(ACCOUNT_NAME, download.user.accountName) - putExtra(EXTRA_REMOTE_PATH, download.remotePath) - putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) - putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) - putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) - if (unlinkedFromRemotePath != null) { - putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) - } - setPackage(context.packageName) + notificationManager.setContentIntent(intents.detailsIntent(null), PendingIntent.FLAG_IMMUTABLE) } - localBroadcastManager.sendBroadcast(intent) + notificationManager.notifyForResult(downloadResult, download) } private fun dismissDownloadInProgressNotification() { @@ -430,82 +313,7 @@ class FilesDownloadWorker( } } - notificationManager.cancel(R.string.downloader_download_in_progress_ticker) - } - - private fun configureUpdateCredentialsNotification(user: User) { - val intent = Intent(context, AuthenticatorActivity::class.java).apply { - putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) - putExtra( - AuthenticatorActivity.EXTRA_ACTION, - AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN - ) - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) - addFlags(Intent.FLAG_FROM_BACKGROUND) - } - - notificationBuilder.setContentIntent( - PendingIntent.getActivity( - context, System.currentTimeMillis().toInt(), - intent, - PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE - ) - ) - } - - private fun configureNotificationBuilderForDownloadStart(download: DownloadFileOperation) { - notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) - .setSmallIcon(R.drawable.notification_icon) - .setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) - .setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) - .setOngoing(true) - .setProgress(100, 0, download.size < 0) - .setContentText( - String.format( - context.getString(R.string.downloader_download_in_progress_content), 0, - File(download.savePath).name - ) - ) - } - - private fun showDetailsIntent(operation: DownloadFileOperation?) { - val intent: Intent = if (operation != null) { - if (PreviewImageFragment.canBePreviewed(operation.file)) { - Intent(context, PreviewImageActivity::class.java) - } else { - Intent(context, FileDisplayActivity::class.java) - }.apply { - putExtra(FileActivity.EXTRA_FILE, operation.file) - putExtra(FileActivity.EXTRA_USER, operation.user) - flags = Intent.FLAG_ACTIVITY_CLEAR_TOP - } - } else { - Intent() - } - - notificationBuilder.setContentIntent( - PendingIntent.getActivity( - context, - System.currentTimeMillis().toInt(), - intent, - PendingIntent.FLAG_IMMUTABLE - ) - ) - } - - private fun sendBroadcastNewDownload( - download: DownloadFileOperation, - linkedToRemotePath: String - ) { - val intent = Intent(getDownloadAddedMessage()).apply { - putExtra(ACCOUNT_NAME, download.user.accountName) - putExtra(EXTRA_REMOTE_PATH, download.remotePath) - putExtra(EXTRA_LINKED_TO_PATH, linkedToRemotePath) - setPackage(context.packageName) - } - - localBroadcastManager.sendBroadcast(intent) + notificationManager.dismissDownloadInProgressNotification() } override fun onAccountsUpdated(accounts: Array?) { @@ -514,6 +322,7 @@ class FilesDownloadWorker( } } + @Suppress("MagicNumber") override fun onTransferProgress( progressRate: Long, totalTransferredSoFar: Long, @@ -523,25 +332,13 @@ class FilesDownloadWorker( val percent: Int = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt() if (percent != lastPercent) { - notificationBuilder.setProgress(100, percent, totalToTransfer < 0) - val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) - val text = - String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) - notificationBuilder.setContentText(text) - - notifyDownloadInProgressNotification() + notificationManager.updateDownloadProgressNotification(filePath, percent, totalToTransfer) + notificationManager.showDownloadInProgressNotification() } lastPercent = percent } - private fun notifyDownloadInProgressNotification() { - notificationManager.notify( - R.string.downloader_download_in_progress_ticker, - notificationBuilder.build() - ) - } - inner class FileDownloaderBinder : Binder(), OnDatatransferProgressListener { private val boundListeners: MutableMap = HashMap() @@ -601,8 +398,10 @@ class FilesDownloadWorker( ) { val listener = boundListeners[currentDownload?.file?.fileId] listener?.onTransferProgress( - progressRate, totalTransferredSoFar, - totalToTransfer, fileName + progressRate, + totalTransferredSoFar, + totalToTransfer, + fileName ) } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 30f7ab3c7595..30b90d1fbe18 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -145,6 +145,7 @@ interface BackgroundJobManager { fun getFileUploads(user: User): LiveData> fun cancelFilesUploadJob(user: User) + @Suppress("LongParameterList") fun startFilesDownloadJob( user: User, ocFile: OCFile, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index bad195010b08..f31f41722311 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -527,7 +527,7 @@ internal class BackgroundJobManagerImpl( FilesDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), FilesDownloadWorker.ACTIVITY_NAME to activityName, FilesDownloadWorker.PACKAGE_NAME to packageName, - FilesDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId, + FilesDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId ) val request = oneTimeRequestBuilder(FilesDownloadWorker::class, JOB_FILES_DOWNLOAD, user) diff --git a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt new file mode 100644 index 000000000000..0bd056e19cbb --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt @@ -0,0 +1,175 @@ +/* + * 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 . + */ + +package com.nextcloud.client.notifications.download + +import android.app.Notification +import android.app.NotificationManager +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.graphics.BitmapFactory +import android.os.Build +import androidx.core.app.NotificationCompat +import com.nextcloud.client.account.User +import com.owncloud.android.R +import com.owncloud.android.authentication.AuthenticatorActivity +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.resources.files.FileUtils +import com.owncloud.android.operations.DownloadFileOperation +import com.owncloud.android.ui.notifications.NotificationUtils +import com.owncloud.android.utils.ErrorMessageAdapter +import com.owncloud.android.utils.theme.ViewThemeUtils +import java.io.File +import java.security.SecureRandom + +class DownloadNotificationManager(private val context: Context, private val viewThemeUtils: ViewThemeUtils) { + + private var notification: Notification? = null + private lateinit var notificationBuilder: NotificationCompat.Builder + private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + + fun init() { + notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) + .setContentTitle(context.resources.getString(R.string.app_name)) + .setContentText(context.resources.getString(R.string.foreground_service_download)) + .setSmallIcon(R.drawable.notification_icon) + .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + } + + notification = notificationBuilder.build() + } + + @Suppress("MagicNumber") + fun notifyForStart(operation: DownloadFileOperation) { + notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) + .setSmallIcon(R.drawable.notification_icon) + .setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) + .setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) + .setOngoing(true) + .setProgress(100, 0, operation.size < 0) + .setContentText( + String.format( + context.getString(R.string.downloader_download_in_progress_content), 0, + File(operation.savePath).name + ) + ) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + } + } + + @Suppress("MagicNumber") + fun notifyForResult(result: RemoteOperationResult<*>, download: DownloadFileOperation) { + val errorMessage = ErrorMessageAdapter.getErrorCauseMessage( + result, + download, + context.resources + ) + + notificationBuilder.setContentText(errorMessage) + + notificationManager.notify(SecureRandom().nextInt(), notificationBuilder.build()) + + if (result.isSuccess) { + NotificationUtils.cancelWithDelay( + notificationManager, + R.string.downloader_download_succeeded_ticker, + 2000 + ) + } + } + + fun prepareForResult( + downloadResult: RemoteOperationResult<*>, + needsToUpdateCredentials: Boolean + ) { + var tickerId = + if (downloadResult.isSuccess) { + R.string.downloader_download_succeeded_ticker + } else { + R.string.downloader_download_failed_ticker + } + + tickerId = if (needsToUpdateCredentials) { + R.string.downloader_download_failed_credentials_error + } else { + tickerId + } + + notificationBuilder + .setTicker(context.getString(tickerId)) + .setContentTitle(context.getString(tickerId)) + .setAutoCancel(true) + .setOngoing(false) + .setProgress(0, 0, false) + } + + @Suppress("MagicNumber") + fun updateDownloadProgressNotification(filePath: String, percent: Int, totalToTransfer: Long) { + notificationBuilder.setProgress(100, percent, totalToTransfer < 0) + val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) + val text = + String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) + notificationBuilder.setContentText(text) + } + + fun showDownloadInProgressNotification() { + notificationManager.notify( + R.string.downloader_download_in_progress_ticker, + notificationBuilder.build() + ) + } + + fun dismissDownloadInProgressNotification() { + notificationManager.cancel(R.string.downloader_download_in_progress_ticker) + } + + fun setCredentialContentIntent(user: User) { + val intent = Intent(context, AuthenticatorActivity::class.java).apply { + putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) + putExtra( + AuthenticatorActivity.EXTRA_ACTION, + AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN + ) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + addFlags(Intent.FLAG_FROM_BACKGROUND) + } + + setContentIntent(intent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE) + } + + fun setContentIntent(intent: Intent, flag: Int) { + notificationBuilder.setContentIntent( + PendingIntent.getActivity( + context, + System.currentTimeMillis().toInt(), + intent, + flag + ) + ) + } +} From 1a7e8cbef1d979c135ba0ae05fbfb64ba3acf4eb Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Dec 2023 14:15:30 +0100 Subject: [PATCH 107/189] Solve git conflicts Signed-off-by: alperozturk --- .../nextcloud/client/files/downloader/FilesDownloadIntents.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt index d8d6e67a2c8f..4c5a5b2c780c 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt @@ -80,4 +80,5 @@ class FilesDownloadIntents(private val context: Context) { Intent() } } + } From 1775e342fb9feb11bfe1e28ced41b60eeb4ed11a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 09:17:16 +0100 Subject: [PATCH 108/189] Create download worker Signed-off-by: alperozturk --- .../client/files/downloader/DownloadWorker.kt | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt new file mode 100644 index 000000000000..70cfe01e674a --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt @@ -0,0 +1,39 @@ +/* + * 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 . + */ + +package com.nextcloud.client.files.downloader + +import android.content.Context +import android.content.Intent +import androidx.work.Worker +import androidx.work.WorkerParameters +import com.owncloud.android.files.services.FileDownloader + +class DownloadWorker( + private val context: Context, + params: WorkerParameters, + private val intent: Intent, + private val fileDownloader: FileDownloader, +) : Worker(context, params) { + override fun doWork(): Result { + TODO("Not yet implemented") + } +} From b8b3d6590787a79e61895e2e27ea14d9f33c0265 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 10:44:55 +0100 Subject: [PATCH 109/189] Implement files download worker constructor Signed-off-by: alperozturk --- .../client/files/downloader/DownloadWorker.kt | 39 ------------------- .../client/jobs/BackgroundJobFactory.kt | 11 ++++++ 2 files changed, 11 insertions(+), 39 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt deleted file mode 100644 index 70cfe01e674a..000000000000 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadWorker.kt +++ /dev/null @@ -1,39 +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 . - */ - -package com.nextcloud.client.files.downloader - -import android.content.Context -import android.content.Intent -import androidx.work.Worker -import androidx.work.WorkerParameters -import com.owncloud.android.files.services.FileDownloader - -class DownloadWorker( - private val context: Context, - params: WorkerParameters, - private val intent: Intent, - private val fileDownloader: FileDownloader, -) : Worker(context, params) { - override fun doWork(): Result { - TODO("Not yet implemented") - } -} diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt index 38debc763eed..9526f41150fe 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt @@ -266,6 +266,17 @@ class BackgroundJobFactory @Inject constructor( ) } + private fun createFilesDownloadWorker(context: Context, params: WorkerParameters): FilesDownloadWorker { + return FilesDownloadWorker( + viewThemeUtils.get(), + accountManager, + uploadsStorageManager, + localBroadcastManager.get(), + context, + params + ) + } + private fun createPDFGenerateWork(context: Context, params: WorkerParameters): GeneratePdfFromImagesWork { return GeneratePdfFromImagesWork( appContext = context, From 546833383e4f65f2fa81d6072993ce2cb60a6c32 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Dec 2023 16:28:37 +0100 Subject: [PATCH 110/189] Use interfaceSerializer Signed-off-by: alperozturk --- .../nextcloud/utils/InterfaceSerializer.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java diff --git a/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java b/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java new file mode 100644 index 000000000000..da253c14d9b5 --- /dev/null +++ b/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java @@ -0,0 +1,56 @@ +/* + * 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 . + */ + +package com.nextcloud.utils; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +import java.lang.reflect.Type; + +final public class InterfaceSerializer implements JsonSerializer, JsonDeserializer { + + private final Class implementationClass; + + private InterfaceSerializer(final Class implementationClass) { + this.implementationClass = implementationClass; + } + + public static InterfaceSerializer interfaceSerializer(final Class implementationClass) { + return new InterfaceSerializer<>(implementationClass); + } + + @Override + public JsonElement serialize(final T value, final Type type, final JsonSerializationContext context) { + final Type targetType = value != null + ? value.getClass() + : type; + return context.serialize(value, targetType); + } + + @Override + public T deserialize(final JsonElement jsonElement, final Type typeOfT, final JsonDeserializationContext context) { + return context.deserialize(jsonElement, implementationClass); + } +} From 180dec7746c7a0fac2e8bfba0bcbea16d3850573 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 20 Dec 2023 09:13:15 +0100 Subject: [PATCH 111/189] Create user from accountName Signed-off-by: alperozturk --- .../nextcloud/utils/InterfaceSerializer.java | 56 ------------------- 1 file changed, 56 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java diff --git a/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java b/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java deleted file mode 100644 index da253c14d9b5..000000000000 --- a/app/src/main/java/com/nextcloud/utils/InterfaceSerializer.java +++ /dev/null @@ -1,56 +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 . - */ - -package com.nextcloud.utils; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; - -import java.lang.reflect.Type; - -final public class InterfaceSerializer implements JsonSerializer, JsonDeserializer { - - private final Class implementationClass; - - private InterfaceSerializer(final Class implementationClass) { - this.implementationClass = implementationClass; - } - - public static InterfaceSerializer interfaceSerializer(final Class implementationClass) { - return new InterfaceSerializer<>(implementationClass); - } - - @Override - public JsonElement serialize(final T value, final Type type, final JsonSerializationContext context) { - final Type targetType = value != null - ? value.getClass() - : type; - return context.serialize(value, targetType); - } - - @Override - public T deserialize(final JsonElement jsonElement, final Type typeOfT, final JsonDeserializationContext context) { - return context.deserialize(jsonElement, implementationClass); - } -} From d8f00fa41c84e793a2d149cdfead44b66e92e3e3 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Dec 2023 14:50:00 +0100 Subject: [PATCH 112/189] Solve git conflicts Signed-off-by: alperozturk --- .../client/files/downloader/FilesDownloadIntents.kt | 1 - .../com/nextcloud/client/jobs/BackgroundJobFactory.kt | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt index 4c5a5b2c780c..d8d6e67a2c8f 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt @@ -80,5 +80,4 @@ class FilesDownloadIntents(private val context: Context) { Intent() } } - } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt index 9526f41150fe..38debc763eed 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt @@ -266,17 +266,6 @@ class BackgroundJobFactory @Inject constructor( ) } - private fun createFilesDownloadWorker(context: Context, params: WorkerParameters): FilesDownloadWorker { - return FilesDownloadWorker( - viewThemeUtils.get(), - accountManager, - uploadsStorageManager, - localBroadcastManager.get(), - context, - params - ) - } - private fun createPDFGenerateWork(context: Context, params: WorkerParameters): GeneratePdfFromImagesWork { return GeneratePdfFromImagesWork( appContext = context, From 113ded1adfbf4a614a633fbafde675d3815f8141 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Dec 2023 15:53:07 +0100 Subject: [PATCH 113/189] Remove Download Service Connections Signed-off-by: alperozturk --- .../com/owncloud/android/ui/activity/FileActivity.java | 9 ++------- .../android/ui/activity/ManageAccountsActivity.java | 10 ---------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index 2a89b567e764..e36c0e9ed2ca 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -168,7 +168,6 @@ public abstract class FileActivity extends DrawerActivity protected FilesDownloadWorker.FileDownloaderBinder mDownloaderBinder; protected FileUploaderBinder mUploaderBinder; - private ServiceConnection mDownloadServiceConnection; private ServiceConnection mUploadServiceConnection; @Inject @@ -234,10 +233,10 @@ protected void onCreate(Bundle savedInstanceState) { bindService(new Intent(this, OperationsService.class), mOperationsServiceConnection, Context.BIND_AUTO_CREATE); - mDownloadServiceConnection = newTransferenceServiceConnection(); - if (mDownloadServiceConnection != null && user != null) { + if (user != null) { new FilesDownloadHelper().downloadFile(user, mFile); } + mUploadServiceConnection = newTransferenceServiceConnection(); if (mUploadServiceConnection != null) { bindService(new Intent(this, FileUploader.class), mUploadServiceConnection, @@ -281,10 +280,6 @@ protected void onDestroy() { unbindService(mOperationsServiceConnection); mOperationsServiceBinder = null; } - if (mDownloadServiceConnection != null) { - unbindService(mDownloadServiceConnection); - mDownloadServiceConnection = null; - } if (mUploadServiceConnection != null) { unbindService(mUploadServiceConnection); mUploadServiceConnection = null; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 1cd495dfee49..24622e11414a 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -105,7 +105,6 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap private final Handler handler = new Handler(); private String accountName; private UserListAdapter userListAdapter; - private ServiceConnection downloadServiceConnection; private ServiceConnection uploadServiceConnection; private Set originalUsers; private String originalCurrentUser; @@ -241,11 +240,6 @@ private boolean hasCurrentAccountChanged() { * Initialize ComponentsGetters. */ private void initializeComponentGetters() { - downloadServiceConnection = newTransferenceServiceConnection(); - if (downloadServiceConnection != null) { - // FIXME check this usage - // bindService(new Intent(this, FileDownloader.class), downloadServiceConnection, Context.BIND_AUTO_CREATE); - } uploadServiceConnection = newTransferenceServiceConnection(); if (uploadServiceConnection != null) { bindService(new Intent(this, FileUploader.class), uploadServiceConnection, @@ -374,10 +368,6 @@ public void run(AccountManagerFuture future) { @Override protected void onDestroy() { - if (downloadServiceConnection != null) { - unbindService(downloadServiceConnection); - downloadServiceConnection = null; - } if (uploadServiceConnection != null) { unbindService(uploadServiceConnection); uploadServiceConnection = null; From 860e619a63021c345a53b98a928f5b5f267096a3 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 12:56:21 +0100 Subject: [PATCH 114/189] Rebase master Signed-off-by: alperozturk --- .../files/downloader/TransferManagerTest.kt | 2 +- .../android/files/FileMenuFilterIT.kt | 4 +- .../java/com/nextcloud/test/TestActivity.kt | 4 +- app/src/main/AndroidManifest.xml | 2 +- .../com/nextcloud/client/di/AppComponent.java | 4 +- .../nextcloud/client/di/ComponentsModule.java | 2 - .../client/files/downloader/DownloadTask.kt | 4 +- .../files/downloader/FileDownloadHelper.kt | 104 +++-- .../files/downloader/FileDownloadIntents.kt | 19 +- .../files/downloader/FileDownloadWorker.kt | 394 ++++++----------- .../files/downloader/FilesDownloadHelper.kt | 150 ------- .../files/downloader/FilesDownloadIntents.kt | 83 ---- .../files/downloader/FilesDownloadWorker.kt | 408 ------------------ .../files/transfer/TransferManagerImpl.kt | 4 +- .../client/jobs/BackgroundJobFactory.kt | 8 +- .../client/jobs/BackgroundJobManagerImpl.kt | 18 +- .../nextcloud/client/jobs/FilesExportWork.kt | 4 +- .../android/files/FileMenuFilter.java | 6 +- .../operations/SynchronizeFileOperation.java | 4 +- .../SynchronizeFolderOperation.java | 4 +- .../providers/DocumentsStorageProvider.java | 2 +- .../android/services/SyncFolderHandler.java | 16 +- .../android/ui/activity/ComponentsGetter.java | 4 +- .../ui/activity/ConflictsResolveActivity.kt | 4 +- .../android/ui/activity/FileActivity.java | 10 +- .../ui/activity/FileDisplayActivity.java | 32 +- .../ui/activity/ManageAccountsActivity.java | 8 +- .../ui/fragment/FileDetailFragment.java | 8 +- .../ui/helpers/FileOperationsHelper.java | 4 +- .../ui/preview/PreviewImageActivity.java | 22 +- .../ui/preview/PreviewMediaFragment.java | 4 +- 31 files changed, 283 insertions(+), 1059 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt delete mode 100644 app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt delete mode 100644 app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt diff --git a/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt b/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt index 39cdf9c02ebd..ef5e692d8084 100644 --- a/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt +++ b/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt @@ -107,7 +107,7 @@ class TransferManagerTest { private fun createMockTask(): DownloadTask { val task = mockk() - every { task.download(any(), any(), any()) } answers { + every { task.download(any()) } answers { taskProgress.forEach { arg>(1).invoke(it) } diff --git a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt index e031d92ccafe..5e48d0b9647d 100644 --- a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt @@ -23,7 +23,7 @@ package com.owncloud.android.files import androidx.test.core.app.launchActivity import androidx.test.ext.junit.runners.AndroidJUnit4 import com.nextcloud.client.account.User -import com.nextcloud.client.files.downloader.FilesDownloadWorker +import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.test.TestActivity import com.nextcloud.utils.EditorUtils import com.owncloud.android.AbstractIT @@ -62,7 +62,7 @@ class FileMenuFilterIT : AbstractIT() { private lateinit var mockFileUploaderBinder: FileUploader.FileUploaderBinder @MockK - private lateinit var mockFileDownloaderBinder: FilesDownloadWorker.FileDownloaderBinder + private lateinit var mockFileDownloaderBinder: FileDownloadWorker.FileDownloaderBinder @MockK private lateinit var mockOperationsServiceBinder: OperationsService.OperationsServiceBinder diff --git a/app/src/debug/java/com/nextcloud/test/TestActivity.kt b/app/src/debug/java/com/nextcloud/test/TestActivity.kt index 90c4ecc19a82..ec98df551af0 100644 --- a/app/src/debug/java/com/nextcloud/test/TestActivity.kt +++ b/app/src/debug/java/com/nextcloud/test/TestActivity.kt @@ -25,7 +25,7 @@ import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment import androidx.swiperefreshlayout.widget.SwipeRefreshLayout -import com.nextcloud.client.files.downloader.FilesDownloadWorker +import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.client.network.Connectivity import com.nextcloud.client.network.ConnectivityService import com.nextcloud.utils.EditorUtils @@ -130,7 +130,7 @@ class TestActivity : return null } - override fun getFileDownloaderBinder(): FilesDownloadWorker.FileDownloaderBinder? { + override fun getFileDownloaderBinder(): FileDownloadWorker.FileDownloaderBinder? { return null } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3d9cb464745e..f83f59ef32fd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -394,7 +394,7 @@ android:name=".services.OperationsService" android:exported="false" /> Unit, isCancelled: IsCancelled): Result { + fun download(request: DownloadRequest): Result { val op = DownloadFileOperation(request.user, request.file, context) val client = clientProvider.invoke() val result = op.execute(client) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 9984549be9da..bd8b8417d9ea 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -41,51 +41,10 @@ class FileDownloadHelper { @Inject lateinit var uploadsStorageManager: UploadsStorageManager - companion object { - private var instance: FileDownloadHelper? = null - - fun instance(): FileDownloadHelper { - return instance ?: synchronized(this) { - instance ?: FileDownloadHelper().also { instance = it } - } - } - } - init { MainApp.getAppComponent().inject(this) } - fun isDownloading(user: User?, file: OCFile?): Boolean { - if (user == null || file == null) { - return false - } - - return backgroundJobManager.isStartFileDownloadJobScheduled(user, file.fileId) || - backgroundJobManager.isStartFileDownloadJobScheduled(user, file.parentId) - } - - fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { - if (user == null || file == null) return - - FileDownloadWorker.cancelOperation(user.accountName, file.fileId) - backgroundJobManager.cancelFilesDownloadJob(user, file.fileId) - } - - fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation?) { - if (accountName == null || currentDownload == null) return - - val currentUser = currentDownload.user - val currentFile = currentDownload.file - - if (!currentUser.nameEquals(accountName)) { - return - } - - currentDownload.cancel() - FileDownloadWorker.cancelOperation(currentUser.accountName, currentFile.fileId) - backgroundJobManager.cancelFilesDownloadJob(currentUser, currentFile.fileId) - } - fun saveFile( file: OCFile, currentDownload: DownloadFileOperation?, @@ -120,32 +79,65 @@ class FileDownloadHelper { storageManager?.saveConflict(file, null) } - fun downloadFileIfNotStartedBefore(user: User, file: OCFile) { - if (!isDownloading(user, file)) { - downloadFile(user, file, downloadType = DownloadType.DOWNLOAD) - } + fun downloadFile(user: User, ocFile: OCFile) { + backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + "", + DownloadType.DOWNLOAD, + "", + "", + null + ) + } + + fun downloadFile(user: User, ocFile: OCFile, behaviour: String) { + backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + behaviour, + DownloadType.DOWNLOAD, + "", + "", + null + ) } - fun downloadFolder(folder: OCFile, user: User, files: List) { - val filesPath = files.map { it.remotePath } - backgroundJobManager.startFolderDownloadJob(folder, user, filesPath) + fun downloadFile(user: User, ocFile: OCFile, downloadType: DownloadType) { + backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + "", + downloadType, + "", + "", + null + ) } - fun downloadFile(user: User, file: OCFile) { - downloadFile(user, file, downloadType = DownloadType.DOWNLOAD) + fun downloadFile(user: User, ocFile: OCFile, conflictUploadId: Long) { + backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + "", + DownloadType.DOWNLOAD, + "", + "", + conflictUploadId + ) } @Suppress("LongParameterList") fun downloadFile( user: User, ocFile: OCFile, - behaviour: String = "", - downloadType: DownloadType? = DownloadType.DOWNLOAD, - activityName: String = "", - packageName: String = "", - conflictUploadId: Long? = null + behaviour: String, + downloadType: DownloadType?, + activityName: String, + packageName: String, + conflictUploadId: Long? ) { - backgroundJobManager.startFileDownloadJob( + backgroundJobManager.startFilesDownloadJob( user, ocFile, behaviour, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt index 78f15a07291d..9725bbd69dda 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt @@ -23,8 +23,6 @@ package com.nextcloud.client.files.downloader import android.content.Context import android.content.Intent -import com.nextcloud.client.account.User -import com.owncloud.android.authentication.AuthenticatorActivity import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.ui.activity.FileActivity @@ -41,7 +39,7 @@ class FileDownloadIntents(private val context: Context) { linkedToRemotePath: String ): Intent { return Intent(FileDownloadWorker.getDownloadAddedMessage()).apply { - putExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME, download.user.accountName) + putExtra(FileDownloadWorker.ACCOUNT_NAME, download.user.accountName) putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) putExtra(FileDownloadWorker.EXTRA_LINKED_TO_PATH, linkedToRemotePath) setPackage(context.packageName) @@ -55,7 +53,7 @@ class FileDownloadIntents(private val context: Context) { ): Intent { return Intent(FileDownloadWorker.getDownloadFinishMessage()).apply { putExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) - putExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME, download.user.accountName) + putExtra(FileDownloadWorker.ACCOUNT_NAME, download.user.accountName) putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) @@ -67,19 +65,6 @@ class FileDownloadIntents(private val context: Context) { } } - fun credentialContentIntent(user: User): Intent { - return Intent(context, AuthenticatorActivity::class.java).apply { - putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) - putExtra( - AuthenticatorActivity.EXTRA_ACTION, - AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN - ) - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) - addFlags(Intent.FLAG_FROM_BACKGROUND) - } - } - fun detailsIntent(operation: DownloadFileOperation?): Intent { return if (operation != null) { if (PreviewImageFragment.canBePreviewed(operation.file)) { diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 4a26190830db..65afdab5f26c 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -26,23 +26,23 @@ import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener import android.app.PendingIntent import android.content.Context -import androidx.core.util.component1 -import androidx.core.util.component2 +import android.os.Binder +import android.os.IBinder +import android.util.Pair import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters +import com.google.gson.Gson import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional -import com.nextcloud.model.WorkerState -import com.nextcloud.model.WorkerStateLiveData -import com.nextcloud.utils.ForegroundServiceHelper -import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager -import com.owncloud.android.datamodel.ForegroundServiceType import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.files.services.IndexedForest import com.owncloud.android.lib.common.OwnCloudAccount +import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.OwnCloudClientManagerFactory import com.owncloud.android.lib.common.network.OnDatatransferProgressListener import com.owncloud.android.lib.common.operations.RemoteOperationResult @@ -51,14 +51,14 @@ import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType import com.owncloud.android.utils.theme.ViewThemeUtils -import java.security.SecureRandom import java.util.AbstractList import java.util.Vector -@Suppress("LongParameterList", "TooManyFunctions") +@Suppress("LongParameterList") class FileDownloadWorker( private val viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, + private val uploadsStorageManager: UploadsStorageManager, private var localBroadcastManager: LocalBroadcastManager, private val context: Context, params: WorkerParameters @@ -67,30 +67,19 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName - private val pendingDownloads = IndexedForest() - - fun cancelOperation(accountName: String, fileId: Long) { - pendingDownloads.all.forEach { - it.value.payload?.cancelMatchingOperation(accountName, fileId) - } - } - - const val WORKER_ID = "WORKER_ID" - const val FILES_SEPARATOR = "," - const val FOLDER_REMOTE_PATH = "FOLDER_REMOTE_PATH" - const val FILE_REMOTE_PATH = "FILE_REMOTE_PATH" - const val FILES_REMOTE_PATH = "FILES_REMOTE_PATH" - const val ACCOUNT_NAME = "ACCOUNT_NAME" + const val USER_NAME = "USER" + const val FILE = "FILE" const val BEHAVIOUR = "BEHAVIOUR" const val DOWNLOAD_TYPE = "DOWNLOAD_TYPE" const val ACTIVITY_NAME = "ACTIVITY_NAME" const val PACKAGE_NAME = "PACKAGE_NAME" const val CONFLICT_UPLOAD_ID = "CONFLICT_UPLOAD_ID" - - const val EXTRA_DOWNLOAD_RESULT = "EXTRA_DOWNLOAD_RESULT" - const val EXTRA_REMOTE_PATH = "EXTRA_REMOTE_PATH" - const val EXTRA_LINKED_TO_PATH = "EXTRA_LINKED_TO_PATH" - const val EXTRA_ACCOUNT_NAME = "EXTRA_ACCOUNT_NAME" + const val EXTRA_USER = "USER" + const val EXTRA_FILE = "FILE" + const val EXTRA_DOWNLOAD_RESULT = "RESULT" + const val EXTRA_REMOTE_PATH = "REMOTE_PATH" + const val EXTRA_LINKED_TO_PATH = "LINKED_TO" + const val ACCOUNT_NAME = "ACCOUNT_NAME" fun getDownloadAddedMessage(): String { return FileDownloadWorker::class.java.name + "DOWNLOAD_ADDED" @@ -102,223 +91,116 @@ class FileDownloadWorker( } private var currentDownload: DownloadFileOperation? = null - private var conflictUploadId: Long? = null private var lastPercent = 0 - private val intents = FileDownloadIntents(context) - private lateinit var notificationManager: DownloadNotificationManager - private var downloadProgressListener = FileDownloadProgressListener() - - private var user: User? = null + private val notificationManager = DownloadNotificationManager(context, viewThemeUtils) + private val pendingDownloads = IndexedForest() + private var downloadBinder: IBinder = FileDownloaderBinder() private var currentUser = Optional.empty() - - private var currentUserFileStorageManager: FileDataStorageManager? = null - private var fileDataStorageManager: FileDataStorageManager? = null - - private var workerId: Int? = null - private var folder: OCFile? = null - private var isAnyOperationFailed = false + private val helper = FileDownloadHelper() + private var startedDownload = false + private var storageManager: FileDataStorageManager? = null + private var downloadClient: OwnCloudClient? = null + private val gson = Gson() @Suppress("TooGenericExceptionCaught") override fun doWork(): Result { return try { val requestDownloads = getRequestDownloads() - notificationManager = - DownloadNotificationManager(workerId ?: SecureRandom().nextInt(), context, viewThemeUtils) + notificationManager.init() addAccountUpdateListener() - - val foregroundInfo = ForegroundServiceHelper.createWorkerForegroundInfo( - notificationManager.getId(), - notificationManager.getNotification(), - ForegroundServiceType.DataSync - ) - setForegroundAsync(foregroundInfo) - - requestDownloads.forEach { - downloadFile(it) - } - - showSuccessNotification() - setIdleWorkerState() + startDownloadForEachRequest(requestDownloads) Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() } catch (t: Throwable) { - notificationManager.showCompleteNotification(context.getString(R.string.downloader_unexpected_error)) Log_OC.e(TAG, "Error caught at FilesDownloadWorker(): " + t.localizedMessage) - setIdleWorkerState() Result.failure() } } - override fun onStopped() { - Log_OC.e(TAG, "FilesDownloadWorker stopped") - - notificationManager.dismissNotification() - cancelAllDownloads() - removePendingDownload(currentDownload?.user?.accountName) - setIdleWorkerState() - - super.onStopped() - } - - private fun setWorkerState(user: User?) { - WorkerStateLiveData.instance().setWorkState(WorkerState.Download(user, currentDownload)) - } - - private fun setIdleWorkerState() { - currentDownload = null - WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) - } - - private fun cancelAllDownloads() { - pendingDownloads.all.forEach { - it.value.payload?.cancel() - } - } - - private fun removePendingDownload(accountName: String?) { - pendingDownloads.remove(accountName) - } - - @Suppress("MagicNumber") - private fun showSuccessNotification() { - if (isAnyOperationFailed) { - notificationManager.dismissNotification() - return - } - - val successText = if (folder != null) { - context.getString(R.string.downloader_folder_downloaded, folder?.fileName) - } else if (currentDownload?.file != null) { - context.getString(R.string.downloader_file_downloaded, currentDownload?.file?.fileName) - } else { - context.getString(R.string.downloader_download_completed) - } - - notificationManager.showCompleteNotification(successText) - } - private fun getRequestDownloads(): AbstractList { - workerId = inputData.keyValueMap[WORKER_ID] as Int - - isAnyOperationFailed = false - setUser() - setFolder() - val files = getFiles() - val downloadType = getDownloadType() - conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? - val behaviour = inputData.keyValueMap[BEHAVIOUR] as String? ?: "" - val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String? ?: "" - val packageName = inputData.keyValueMap[PACKAGE_NAME] as String? ?: "" + val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) + val accountName = inputData.keyValueMap[USER_NAME] as String + val user = accountManager.getUser(accountName).get() + val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? + val downloadType = if (downloadTypeAsString != null) { + if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { + DownloadType.DOWNLOAD + } else { + DownloadType.EXPORT + } + } else { + null + } + val behaviour = inputData.keyValueMap[BEHAVIOUR] as String + val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String + val packageName = inputData.keyValueMap[PACKAGE_NAME] as String val requestedDownloads: AbstractList = Vector() - return try { - files.forEach { file -> - val operation = DownloadFileOperation( - user, - file, - behaviour, - activityName, - packageName, - context, - downloadType - ) - - operation.addDownloadDataTransferProgressListener(this) - operation.addDownloadDataTransferProgressListener(downloadProgressListener) - val (downloadKey, linkedToRemotePath) = pendingDownloads.putIfAbsent( - user?.accountName, - file.remotePath, - operation - ) - - if (downloadKey != null) { - requestedDownloads.add(downloadKey) - localBroadcastManager.sendBroadcast(intents.newDownloadIntent(operation, linkedToRemotePath)) - } - } + try { + val operation = DownloadFileOperation( + user, + file, + behaviour, + activityName, + packageName, + context, + downloadType + ) + operation.addDatatransferProgressListener(this) + operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder) + val putResult = pendingDownloads.putIfAbsent( + user?.accountName, + file.remotePath, + operation + ) - requestedDownloads + if (putResult != null) { + val downloadKey = putResult.first + requestedDownloads.add(downloadKey) + localBroadcastManager.sendBroadcast(intents.newDownloadIntent(operation, putResult.second)) + } } catch (e: IllegalArgumentException) { Log_OC.e(TAG, "Not enough information provided in intent: " + e.message) - requestedDownloads } - } - private fun setUser() { - val accountName = inputData.keyValueMap[ACCOUNT_NAME] as String - user = accountManager.getUser(accountName).get() - fileDataStorageManager = FileDataStorageManager(user, context.contentResolver) + return requestedDownloads } - private fun setFolder() { - val folderPath = inputData.keyValueMap[FOLDER_REMOTE_PATH] as? String? - if (folderPath != null) { - folder = fileDataStorageManager?.getFileByEncryptedRemotePath(folderPath) - } + private fun addAccountUpdateListener() { + val am = AccountManager.get(context) + am.addOnAccountsUpdatedListener(this, null, false) } - private fun getFiles(): List { - val result = arrayListOf() - - val filesPath = inputData.keyValueMap[FILES_REMOTE_PATH] as String? - val filesPathList = filesPath?.split(FILES_SEPARATOR) + private fun startDownloadForEachRequest(requestDownloads: AbstractList) { + val it: Iterator = requestDownloads.iterator() - if (filesPathList != null) { - filesPathList.forEach { - fileDataStorageManager?.getFileByEncryptedRemotePath(it)?.let { file -> - result.add(file) - } - } - } else { - val remotePath = inputData.keyValueMap[FILE_REMOTE_PATH] as String - fileDataStorageManager?.getFileByEncryptedRemotePath(remotePath)?.let { file -> - result.add(file) - } + while (it.hasNext()) { + val next = it.next() + Log_OC.e(TAG, "Download Key: $next") + downloadFile(next) } - return result - } - - private fun getDownloadType(): DownloadType? { - val typeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? - return if (typeAsString != null) { - if (typeAsString == DownloadType.DOWNLOAD.toString()) { - DownloadType.DOWNLOAD - } else { - DownloadType.EXPORT - } - } else { - null - } - } - - private fun addAccountUpdateListener() { - val am = AccountManager.get(context) - am.addOnAccountsUpdatedListener(this, null, false) + startedDownload = false } @Suppress("TooGenericExceptionCaught") private fun downloadFile(downloadKey: String) { + startedDownload = true currentDownload = pendingDownloads.get(downloadKey) if (currentDownload == null) { return } - val fileName = currentDownload?.file?.fileName - - setWorkerState(user) - Log_OC.e(TAG, "FilesDownloadWorker downloading: $downloadKey") - val isAccountExist = accountManager.exists(currentDownload?.user?.toPlatformAccount()) if (!isAccountExist) { - removePendingDownload(currentDownload?.user?.accountName) + cancelPendingDownloads(currentDownload?.user?.accountName) return } @@ -326,30 +208,33 @@ class FileDownloadWorker( var downloadResult: RemoteOperationResult<*>? = null try { val ocAccount = getOCAccountForDownload() - val downloadClient = + downloadClient = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, context) downloadResult = currentDownload?.execute(downloadClient) if (downloadResult?.isSuccess == true && currentDownload?.downloadType === DownloadType.DOWNLOAD) { getCurrentFile()?.let { - FileDownloadHelper.instance().saveFile(it, currentDownload, currentUserFileStorageManager) + helper.saveFile(it, currentDownload, storageManager) } } } catch (e: Exception) { Log_OC.e(TAG, "Error downloading", e) downloadResult = RemoteOperationResult(e) } finally { - cleanupDownloadProcess(downloadResult, fileName) + cleanupDownloadProcess(downloadResult) } } + private fun cancelPendingDownloads(accountName: String?) { + pendingDownloads.remove(accountName) + } + private fun notifyDownloadStart(download: DownloadFileOperation) { lastPercent = 0 - notificationManager.run { - prepareForStart(download) - setContentIntent(intents.detailsIntent(download), PendingIntent.FLAG_IMMUTABLE) - } + notificationManager.notifyForStart(download) + notificationManager.setContentIntent(intents.detailsIntent(download), PendingIntent.FLAG_IMMUTABLE) + notificationManager.showDownloadInProgressNotification() } private fun getOCAccountForDownload(): OwnCloudAccount { @@ -357,16 +242,16 @@ class FileDownloadWorker( val currentDownloadUser = accountManager.getUser(currentDownloadAccount?.name) if (currentUser != currentDownloadUser) { currentUser = currentDownloadUser - currentUserFileStorageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) + storageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) } return currentDownloadUser.get().toOwnCloudAccount() } private fun getCurrentFile(): OCFile? { - var file: OCFile? = currentDownload?.file?.fileId?.let { currentUserFileStorageManager?.getFileById(it) } + var file: OCFile? = currentDownload?.file?.fileId?.let { storageManager?.getFileById(it) } if (file == null) { - file = currentUserFileStorageManager?.getFileByDecryptedRemotePath(currentDownload?.file?.remotePath) + file = storageManager?.getFileByDecryptedRemotePath(currentDownload?.file?.remotePath) } if (file == null) { @@ -377,11 +262,7 @@ class FileDownloadWorker( return file } - private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?, fileName: String?) { - result?.let { - showFailedDownloadNotifications(it, fileName) - } - + private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { val removeResult = pendingDownloads.removePayload( currentDownload?.user?.accountName, currentDownload?.remotePath @@ -391,39 +272,15 @@ class FileDownloadWorker( currentDownload?.run { notifyDownloadResult(this, downloadResult) - val downloadFinishedIntent = intents.downloadFinishedIntent( this, downloadResult, removeResult.second ) - localBroadcastManager.sendBroadcast(downloadFinishedIntent) } } - private fun showFailedDownloadNotifications(result: RemoteOperationResult<*>, fileName: String?) { - if (result.isSuccess) { - return - } - - isAnyOperationFailed = true - - val failMessage = if (result.isCancelled) { - context.getString( - R.string.downloader_file_download_cancelled, - fileName - ) - } else { - context.getString( - R.string.downloader_file_download_failed, - fileName - ) - } - - notificationManager.showNewNotification(failMessage) - } - private fun notifyDownloadResult( download: DownloadFileOperation, downloadResult: RemoteOperationResult<*> @@ -432,20 +289,31 @@ class FileDownloadWorker( return } + if (downloadResult.isSuccess) { + dismissDownloadInProgressNotification() + return + } + val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) - notificationManager.run { - prepareForResult() - - if (needsToUpdateCredentials) { - showNewNotification(context.getString(R.string.downloader_download_failed_credentials_error)) - setContentIntent( - intents.credentialContentIntent(download.user), - PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE - ) - } else { - setContentIntent(intents.detailsIntent(null), PendingIntent.FLAG_IMMUTABLE) + notificationManager.prepareForResult(downloadResult, needsToUpdateCredentials) + + if (needsToUpdateCredentials) { + notificationManager.setCredentialContentIntent(download.user) + } else { + notificationManager.setContentIntent(intents.detailsIntent(null), PendingIntent.FLAG_IMMUTABLE) + } + + notificationManager.notifyForResult(downloadResult, download) + } + + private fun dismissDownloadInProgressNotification() { + conflictUploadId?.let { + if (it > 0) { + uploadsStorageManager.removeUpload(it) } } + + notificationManager.dismissDownloadInProgressNotification() } override fun onAccountsUpdated(accounts: Array?) { @@ -464,19 +332,43 @@ class FileDownloadWorker( val percent: Int = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt() if (percent != lastPercent) { - notificationManager.run { - updateDownloadProgress(filePath, percent, totalToTransfer) - } + notificationManager.updateDownloadProgressNotification(filePath, percent, totalToTransfer) + notificationManager.showDownloadInProgressNotification() } lastPercent = percent } - inner class FileDownloadProgressListener : OnDatatransferProgressListener { + inner class FileDownloaderBinder : Binder(), OnDatatransferProgressListener { private val boundListeners: MutableMap = HashMap() + fun cancelPendingOrCurrentDownloads(account: Account, file: OCFile) { + val removeResult: Pair = + pendingDownloads.remove(account.name, file.remotePath) + val download = removeResult.first + + if (download != null) { + download.cancel() + } else { + if (currentUser?.isPresent == true && + currentDownload?.remotePath?.startsWith(file.remotePath) == true && + account.name == currentUser.get()?.accountName + ) { + currentDownload?.cancel() + } + } + } + + fun cancelAllDownloadsForAccount(accountName: String?) { + if (currentDownload?.user?.nameEquals(accountName) == true) { + currentDownload?.cancel() + } + + cancelPendingDownloads(accountName) + } + fun isDownloading(user: User?, file: OCFile?): Boolean { - return FileDownloadHelper.instance().isDownloading(user, file) + return user != null && file != null && pendingDownloads.contains(user.accountName, file.remotePath) } fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt deleted file mode 100644 index 328d4b4b164d..000000000000 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadHelper.kt +++ /dev/null @@ -1,150 +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 . - */ - -package com.nextcloud.client.files.downloader - -import com.nextcloud.client.account.User -import com.nextcloud.client.jobs.BackgroundJobManager -import com.owncloud.android.MainApp -import com.owncloud.android.datamodel.FileDataStorageManager -import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.datamodel.UploadsStorageManager -import com.owncloud.android.operations.DownloadFileOperation -import com.owncloud.android.operations.DownloadType -import com.owncloud.android.utils.MimeTypeUtil -import java.io.File -import javax.inject.Inject - -class FilesDownloadHelper { - - @Inject - lateinit var backgroundJobManager: BackgroundJobManager - - @Inject - lateinit var uploadsStorageManager: UploadsStorageManager - - init { - MainApp.getAppComponent().inject(this) - } - - fun saveFile( - file: OCFile, - currentDownload: DownloadFileOperation?, - storageManager: FileDataStorageManager? - ) { - val syncDate = System.currentTimeMillis() - - file.apply { - lastSyncDateForProperties = syncDate - lastSyncDateForData = syncDate - isUpdateThumbnailNeeded = true - modificationTimestamp = currentDownload?.modificationTimestamp ?: 0L - modificationTimestampAtLastSyncForData = currentDownload?.modificationTimestamp ?: 0L - etag = currentDownload?.etag - mimeType = currentDownload?.mimeType - storagePath = currentDownload?.savePath - - val savePathFile = currentDownload?.savePath?.let { File(it) } - savePathFile?.let { - fileLength = savePathFile.length() - } - - remoteId = currentDownload?.file?.remoteId - } - - storageManager?.saveFile(file) - - if (MimeTypeUtil.isMedia(currentDownload?.mimeType)) { - FileDataStorageManager.triggerMediaScan(file.storagePath, file) - } - - storageManager?.saveConflict(file, null) - } - - fun downloadFile(user: User, ocFile: OCFile) { - backgroundJobManager.startFilesDownloadJob( - user, - ocFile, - "", - DownloadType.DOWNLOAD, - "", - "", - null - ) - } - - fun downloadFile(user: User, ocFile: OCFile, behaviour: String) { - backgroundJobManager.startFilesDownloadJob( - user, - ocFile, - behaviour, - DownloadType.DOWNLOAD, - "", - "", - null - ) - } - - fun downloadFile(user: User, ocFile: OCFile, downloadType: DownloadType) { - backgroundJobManager.startFilesDownloadJob( - user, - ocFile, - "", - downloadType, - "", - "", - null - ) - } - - fun downloadFile(user: User, ocFile: OCFile, conflictUploadId: Long) { - backgroundJobManager.startFilesDownloadJob( - user, - ocFile, - "", - DownloadType.DOWNLOAD, - "", - "", - conflictUploadId - ) - } - - @Suppress("LongParameterList") - fun downloadFile( - user: User, - ocFile: OCFile, - behaviour: String, - downloadType: DownloadType?, - activityName: String, - packageName: String, - conflictUploadId: Long? - ) { - backgroundJobManager.startFilesDownloadJob( - user, - ocFile, - behaviour, - downloadType, - activityName, - packageName, - conflictUploadId - ) - } -} diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt deleted file mode 100644 index d8d6e67a2c8f..000000000000 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadIntents.kt +++ /dev/null @@ -1,83 +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 . - */ - -package com.nextcloud.client.files.downloader - -import android.content.Context -import android.content.Intent -import com.owncloud.android.lib.common.operations.RemoteOperationResult -import com.owncloud.android.operations.DownloadFileOperation -import com.owncloud.android.ui.activity.FileActivity -import com.owncloud.android.ui.activity.FileDisplayActivity -import com.owncloud.android.ui.dialog.SendShareDialog -import com.owncloud.android.ui.fragment.OCFileListFragment -import com.owncloud.android.ui.preview.PreviewImageActivity -import com.owncloud.android.ui.preview.PreviewImageFragment - -class FilesDownloadIntents(private val context: Context) { - - fun newDownloadIntent( - download: DownloadFileOperation, - linkedToRemotePath: String - ): Intent { - return Intent(FilesDownloadWorker.getDownloadAddedMessage()).apply { - putExtra(FilesDownloadWorker.ACCOUNT_NAME, download.user.accountName) - putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) - putExtra(FilesDownloadWorker.EXTRA_LINKED_TO_PATH, linkedToRemotePath) - setPackage(context.packageName) - } - } - - fun downloadFinishedIntent( - download: DownloadFileOperation, - downloadResult: RemoteOperationResult<*>, - unlinkedFromRemotePath: String? - ): Intent { - return Intent(FilesDownloadWorker.getDownloadFinishMessage()).apply { - putExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) - putExtra(FilesDownloadWorker.ACCOUNT_NAME, download.user.accountName) - putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) - putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) - putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) - putExtra(SendShareDialog.PACKAGE_NAME, download.packageName) - if (unlinkedFromRemotePath != null) { - putExtra(FilesDownloadWorker.EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath) - } - setPackage(context.packageName) - } - } - - fun detailsIntent(operation: DownloadFileOperation?): Intent { - return if (operation != null) { - if (PreviewImageFragment.canBePreviewed(operation.file)) { - Intent(context, PreviewImageActivity::class.java) - } else { - Intent(context, FileDisplayActivity::class.java) - }.apply { - putExtra(FileActivity.EXTRA_FILE, operation.file) - putExtra(FileActivity.EXTRA_USER, operation.user) - flags = Intent.FLAG_ACTIVITY_CLEAR_TOP - } - } else { - Intent() - } - } -} diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt deleted file mode 100644 index 79bd327cc50a..000000000000 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FilesDownloadWorker.kt +++ /dev/null @@ -1,408 +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 . - */ - -package com.nextcloud.client.files.downloader - -import android.accounts.Account -import android.accounts.AccountManager -import android.accounts.OnAccountsUpdateListener -import android.app.PendingIntent -import android.content.Context -import android.os.Binder -import android.os.IBinder -import android.util.Pair -import androidx.localbroadcastmanager.content.LocalBroadcastManager -import androidx.work.Worker -import androidx.work.WorkerParameters -import com.google.gson.Gson -import com.nextcloud.client.account.User -import com.nextcloud.client.account.UserAccountManager -import com.nextcloud.client.notifications.download.DownloadNotificationManager -import com.nextcloud.java.util.Optional -import com.owncloud.android.datamodel.FileDataStorageManager -import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.datamodel.UploadsStorageManager -import com.owncloud.android.files.services.IndexedForest -import com.owncloud.android.lib.common.OwnCloudAccount -import com.owncloud.android.lib.common.OwnCloudClient -import com.owncloud.android.lib.common.OwnCloudClientManagerFactory -import com.owncloud.android.lib.common.network.OnDatatransferProgressListener -import com.owncloud.android.lib.common.operations.RemoteOperationResult -import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode -import com.owncloud.android.lib.common.utils.Log_OC -import com.owncloud.android.operations.DownloadFileOperation -import com.owncloud.android.operations.DownloadType -import com.owncloud.android.utils.theme.ViewThemeUtils -import java.util.AbstractList -import java.util.Vector - -@Suppress("LongParameterList") -class FilesDownloadWorker( - private val viewThemeUtils: ViewThemeUtils, - private val accountManager: UserAccountManager, - private val uploadsStorageManager: UploadsStorageManager, - private var localBroadcastManager: LocalBroadcastManager, - private val context: Context, - params: WorkerParameters -) : Worker(context, params), OnAccountsUpdateListener, OnDatatransferProgressListener { - - companion object { - private val TAG = FilesDownloadWorker::class.java.simpleName - - const val USER_NAME = "USER" - const val FILE = "FILE" - const val BEHAVIOUR = "BEHAVIOUR" - const val DOWNLOAD_TYPE = "DOWNLOAD_TYPE" - const val ACTIVITY_NAME = "ACTIVITY_NAME" - const val PACKAGE_NAME = "PACKAGE_NAME" - const val CONFLICT_UPLOAD_ID = "CONFLICT_UPLOAD_ID" - const val EXTRA_USER = "USER" - const val EXTRA_FILE = "FILE" - const val EXTRA_DOWNLOAD_RESULT = "RESULT" - const val EXTRA_REMOTE_PATH = "REMOTE_PATH" - const val EXTRA_LINKED_TO_PATH = "LINKED_TO" - const val ACCOUNT_NAME = "ACCOUNT_NAME" - - fun getDownloadAddedMessage(): String { - return FilesDownloadWorker::class.java.name + "DOWNLOAD_ADDED" - } - - fun getDownloadFinishMessage(): String { - return FilesDownloadWorker::class.java.name + "DOWNLOAD_FINISH" - } - } - - private var currentDownload: DownloadFileOperation? = null - private var conflictUploadId: Long? = null - private var lastPercent = 0 - private val intents = FilesDownloadIntents(context) - private val notificationManager = DownloadNotificationManager(context, viewThemeUtils) - private val pendingDownloads = IndexedForest() - private var downloadBinder: IBinder = FileDownloaderBinder() - private var currentUser = Optional.empty() - private val helper = FilesDownloadHelper() - private var startedDownload = false - private var storageManager: FileDataStorageManager? = null - private var downloadClient: OwnCloudClient? = null - private val gson = Gson() - - @Suppress("TooGenericExceptionCaught") - override fun doWork(): Result { - return try { - val requestDownloads = getRequestDownloads() - - notificationManager.init() - addAccountUpdateListener() - startDownloadForEachRequest(requestDownloads) - - Log_OC.e(TAG, "FilesDownloadWorker successfully completed") - Result.success() - } catch (t: Throwable) { - Log_OC.e(TAG, "Error caught at FilesDownloadWorker(): " + t.localizedMessage) - Result.failure() - } - } - - private fun getRequestDownloads(): AbstractList { - conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? - val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) - val accountName = inputData.keyValueMap[USER_NAME] as String - val user = accountManager.getUser(accountName).get() - val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? - val downloadType = if (downloadTypeAsString != null) { - if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { - DownloadType.DOWNLOAD - } else { - DownloadType.EXPORT - } - } else { - null - } - val behaviour = inputData.keyValueMap[BEHAVIOUR] as String - val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String - val packageName = inputData.keyValueMap[PACKAGE_NAME] as String - - val requestedDownloads: AbstractList = Vector() - - try { - val operation = DownloadFileOperation( - user, - file, - behaviour, - activityName, - packageName, - context, - downloadType - ) - operation.addDatatransferProgressListener(this) - operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder) - val putResult = pendingDownloads.putIfAbsent( - user?.accountName, - file.remotePath, - operation - ) - - if (putResult != null) { - val downloadKey = putResult.first - requestedDownloads.add(downloadKey) - localBroadcastManager.sendBroadcast(intents.newDownloadIntent(operation, putResult.second)) - } - } catch (e: IllegalArgumentException) { - Log_OC.e(TAG, "Not enough information provided in intent: " + e.message) - } - - return requestedDownloads - } - - private fun addAccountUpdateListener() { - val am = AccountManager.get(context) - am.addOnAccountsUpdatedListener(this, null, false) - } - - private fun startDownloadForEachRequest(requestDownloads: AbstractList) { - val it: Iterator = requestDownloads.iterator() - - while (it.hasNext()) { - val next = it.next() - Log_OC.e(TAG, "Download Key: $next") - downloadFile(next) - } - - startedDownload = false - } - - @Suppress("TooGenericExceptionCaught") - private fun downloadFile(downloadKey: String) { - startedDownload = true - currentDownload = pendingDownloads.get(downloadKey) - - if (currentDownload == null) { - return - } - - val isAccountExist = accountManager.exists(currentDownload?.user?.toPlatformAccount()) - if (!isAccountExist) { - cancelPendingDownloads(currentDownload?.user?.accountName) - return - } - - notifyDownloadStart(currentDownload!!) - var downloadResult: RemoteOperationResult<*>? = null - try { - val ocAccount = getOCAccountForDownload() - downloadClient = - OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, context) - - downloadResult = currentDownload?.execute(downloadClient) - if (downloadResult?.isSuccess == true && currentDownload?.downloadType === DownloadType.DOWNLOAD) { - getCurrentFile()?.let { - helper.saveFile(it, currentDownload, storageManager) - } - } - } catch (e: Exception) { - Log_OC.e(TAG, "Error downloading", e) - downloadResult = RemoteOperationResult(e) - } finally { - cleanupDownloadProcess(downloadResult) - } - } - - private fun cancelPendingDownloads(accountName: String?) { - pendingDownloads.remove(accountName) - } - - private fun notifyDownloadStart(download: DownloadFileOperation) { - lastPercent = 0 - - notificationManager.notifyForStart(download) - notificationManager.setContentIntent(intents.detailsIntent(download), PendingIntent.FLAG_IMMUTABLE) - notificationManager.showDownloadInProgressNotification() - } - - private fun getOCAccountForDownload(): OwnCloudAccount { - val currentDownloadAccount = currentDownload?.user?.toPlatformAccount() - val currentDownloadUser = accountManager.getUser(currentDownloadAccount?.name) - if (currentUser != currentDownloadUser) { - currentUser = currentDownloadUser - storageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) - } - return currentDownloadUser.get().toOwnCloudAccount() - } - - private fun getCurrentFile(): OCFile? { - var file: OCFile? = currentDownload?.file?.fileId?.let { storageManager?.getFileById(it) } - - if (file == null) { - file = storageManager?.getFileByDecryptedRemotePath(currentDownload?.file?.remotePath) - } - - if (file == null) { - Log_OC.e(this, "Could not save " + currentDownload?.file?.remotePath) - return null - } - - return file - } - - private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { - val removeResult = pendingDownloads.removePayload( - currentDownload?.user?.accountName, - currentDownload?.remotePath - ) - - val downloadResult = result ?: RemoteOperationResult(RuntimeException("Error downloading…")) - - currentDownload?.run { - notifyDownloadResult(this, downloadResult) - val downloadFinishedIntent = intents.downloadFinishedIntent( - this, - downloadResult, - removeResult.second - ) - localBroadcastManager.sendBroadcast(downloadFinishedIntent) - } - } - - private fun notifyDownloadResult( - download: DownloadFileOperation, - downloadResult: RemoteOperationResult<*> - ) { - if (downloadResult.isCancelled) { - return - } - - if (downloadResult.isSuccess) { - dismissDownloadInProgressNotification() - return - } - - val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) - notificationManager.prepareForResult(downloadResult, needsToUpdateCredentials) - - if (needsToUpdateCredentials) { - notificationManager.setCredentialContentIntent(download.user) - } else { - notificationManager.setContentIntent(intents.detailsIntent(null), PendingIntent.FLAG_IMMUTABLE) - } - - notificationManager.notifyForResult(downloadResult, download) - } - - private fun dismissDownloadInProgressNotification() { - conflictUploadId?.let { - if (it > 0) { - uploadsStorageManager.removeUpload(it) - } - } - - notificationManager.dismissDownloadInProgressNotification() - } - - override fun onAccountsUpdated(accounts: Array?) { - if (!accountManager.exists(currentDownload?.user?.toPlatformAccount())) { - currentDownload?.cancel() - } - } - - @Suppress("MagicNumber") - override fun onTransferProgress( - progressRate: Long, - totalTransferredSoFar: Long, - totalToTransfer: Long, - filePath: String - ) { - val percent: Int = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt() - - if (percent != lastPercent) { - notificationManager.updateDownloadProgressNotification(filePath, percent, totalToTransfer) - notificationManager.showDownloadInProgressNotification() - } - - lastPercent = percent - } - - inner class FileDownloaderBinder : Binder(), OnDatatransferProgressListener { - private val boundListeners: MutableMap = HashMap() - - fun cancelPendingOrCurrentDownloads(account: Account, file: OCFile) { - val removeResult: Pair = - pendingDownloads.remove(account.name, file.remotePath) - val download = removeResult.first - - if (download != null) { - download.cancel() - } else { - if (currentUser?.isPresent == true && - currentDownload?.remotePath?.startsWith(file.remotePath) == true && - account.name == currentUser.get()?.accountName - ) { - currentDownload?.cancel() - } - } - } - - fun cancelAllDownloadsForAccount(accountName: String?) { - if (currentDownload?.user?.nameEquals(accountName) == true) { - currentDownload?.cancel() - } - - cancelPendingDownloads(accountName) - } - - fun isDownloading(user: User?, file: OCFile?): Boolean { - return user != null && file != null && pendingDownloads.contains(user.accountName, file.remotePath) - } - - fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { - if (file == null || listener == null) { - return - } - - boundListeners[file.fileId] = listener - } - - fun removeDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { - if (file == null || listener == null) { - return - } - - val fileId = file.fileId - if (boundListeners[fileId] === listener) { - boundListeners.remove(fileId) - } - } - - override fun onTransferProgress( - progressRate: Long, - totalTransferredSoFar: Long, - totalToTransfer: Long, - fileName: String - ) { - val listener = boundListeners[currentDownload?.file?.fileId] - listener?.onTransferProgress( - progressRate, - totalTransferredSoFar, - totalToTransfer, - fileName - ) - } - } -} diff --git a/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerImpl.kt b/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerImpl.kt index 0113002d96d3..8ff6fa24822d 100644 --- a/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerImpl.kt @@ -138,8 +138,8 @@ class TransferManagerImpl( } } else { val downloadTask = downloadTaskFactory.create() - val wrapper: TaskFunction = { progress: ((Int) -> Unit), isCancelled -> - downloadTask.download(request, progress, isCancelled) + val wrapper: TaskFunction = { _: ((Int) -> Unit), _ -> + downloadTask.download(request) } wrapper } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt index 38debc763eed..865b787d5312 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt @@ -34,7 +34,7 @@ import com.nextcloud.client.device.DeviceInfo import com.nextcloud.client.device.PowerManagementService import com.nextcloud.client.documentscan.GeneratePDFUseCase import com.nextcloud.client.documentscan.GeneratePdfFromImagesWork -import com.nextcloud.client.files.downloader.FilesDownloadWorker +import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.client.integrations.deck.DeckApi import com.nextcloud.client.logger.Logger import com.nextcloud.client.network.ConnectivityService @@ -103,7 +103,7 @@ class BackgroundJobFactory @Inject constructor( CalendarImportWork::class -> createCalendarImportWork(context, workerParameters) FilesExportWork::class -> createFilesExportWork(context, workerParameters) FilesUploadWorker::class -> createFilesUploadWorker(context, workerParameters) - FilesDownloadWorker::class -> createFilesDownloadWorker(context, workerParameters) + FileDownloadWorker::class -> createFilesDownloadWorker(context, workerParameters) GeneratePdfFromImagesWork::class -> createPDFGenerateWork(context, workerParameters) HealthStatusWork::class -> createHealthStatusWork(context, workerParameters) TestJob::class -> createTestJob(context, workerParameters) @@ -255,8 +255,8 @@ class BackgroundJobFactory @Inject constructor( ) } - private fun createFilesDownloadWorker(context: Context, params: WorkerParameters): FilesDownloadWorker { - return FilesDownloadWorker( + private fun createFilesDownloadWorker(context: Context, params: WorkerParameters): FileDownloadWorker { + return FileDownloadWorker( viewThemeUtils.get(), accountManager, uploadsStorageManager, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index f31f41722311..8e815432c97a 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -39,7 +39,7 @@ import com.nextcloud.client.account.User import com.nextcloud.client.core.Clock import com.nextcloud.client.di.Injectable import com.nextcloud.client.documentscan.GeneratePdfFromImagesWork -import com.nextcloud.client.files.downloader.FilesDownloadWorker +import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.client.preferences.AppPreferences import com.owncloud.android.datamodel.OCFile import com.owncloud.android.operations.DownloadType @@ -521,16 +521,16 @@ internal class BackgroundJobManagerImpl( val gson = Gson() val data = workDataOf( - FilesDownloadWorker.USER_NAME to user.accountName, - FilesDownloadWorker.FILE to gson.toJson(ocFile), - FilesDownloadWorker.BEHAVIOUR to behaviour, - FilesDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), - FilesDownloadWorker.ACTIVITY_NAME to activityName, - FilesDownloadWorker.PACKAGE_NAME to packageName, - FilesDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId + FileDownloadWorker.USER_NAME to user.accountName, + FileDownloadWorker.FILE to gson.toJson(ocFile), + FileDownloadWorker.BEHAVIOUR to behaviour, + FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), + FileDownloadWorker.ACTIVITY_NAME to activityName, + FileDownloadWorker.PACKAGE_NAME to packageName, + FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId ) - val request = oneTimeRequestBuilder(FilesDownloadWorker::class, JOB_FILES_DOWNLOAD, user) + val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .setInputData(data) .build() diff --git a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt index 797cea1969e4..c5f82cc89df2 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt @@ -33,7 +33,7 @@ import androidx.core.app.NotificationCompat import androidx.work.Worker import androidx.work.WorkerParameters import com.nextcloud.client.account.User -import com.nextcloud.client.files.downloader.FilesDownloadHelper +import com.nextcloud.client.files.downloader.FileDownloadHelper import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -111,7 +111,7 @@ class FilesExportWork( } private fun downloadFile(ocFile: OCFile) { - FilesDownloadHelper().downloadFile( + FileDownloadHelper().downloadFile( user, ocFile, DownloadType.EXPORT diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index e1d9ead64139..f3da5e4b807c 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -31,7 +31,7 @@ import com.nextcloud.android.files.FileLockingHelper; import com.nextcloud.client.account.User; import com.nextcloud.client.editimage.EditImageActivity; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.utils.EditorUtils; import com.owncloud.android.R; import com.owncloud.android.datamodel.FileDataStorageManager; @@ -380,7 +380,7 @@ private boolean anyFileSynchronizing() { if (componentsGetter != null && !files.isEmpty() && user != null) { OperationsServiceBinder opsBinder = componentsGetter.getOperationsServiceBinder(); FileUploaderBinder uploaderBinder = componentsGetter.getFileUploaderBinder(); - FilesDownloadWorker.FileDownloaderBinder downloaderBinder = componentsGetter.getFileDownloaderBinder(); + FileDownloadWorker.FileDownloaderBinder downloaderBinder = componentsGetter.getFileDownloaderBinder(); synchronizing = anyFileSynchronizing(opsBinder) || // comparing local and remote anyFileDownloading(downloaderBinder) || anyFileUploading(uploaderBinder); @@ -398,7 +398,7 @@ private boolean anyFileSynchronizing(OperationsServiceBinder opsBinder) { return synchronizing; } - private boolean anyFileDownloading(FilesDownloadWorker.FileDownloaderBinder downloaderBinder) { + private boolean anyFileDownloading(FileDownloadWorker.FileDownloaderBinder downloaderBinder) { boolean downloading = false; if (downloaderBinder != null) { for (Iterator iterator = files.iterator(); !downloading && iterator.hasNext(); ) { diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java index 1d9228dab52d..48b7aa9b701f 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -25,7 +25,7 @@ import android.text.TextUtils; import com.nextcloud.client.account.User; -import com.nextcloud.client.files.downloader.FilesDownloadHelper; +import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileUploader; @@ -316,7 +316,7 @@ private void requestForUpload(OCFile file) { * @param file OCFile object representing the file to download */ private void requestForDownload(OCFile file) { - FilesDownloadHelper downloadHelper = new FilesDownloadHelper(); + FileDownloadHelper downloadHelper = new FileDownloadHelper(); downloadHelper.downloadFile( mUser, diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index 8aa1e07a765e..cf60dacea912 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -25,7 +25,7 @@ import android.text.TextUtils; import com.nextcloud.client.account.User; -import com.nextcloud.client.files.downloader.FilesDownloadHelper; +import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.owncloud.android.datamodel.DecryptedFolderMetadata; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; @@ -452,7 +452,7 @@ private void startDirectDownloads() throws OperationCancelledException { throw new OperationCancelledException(); } - FilesDownloadHelper downloadHelper = new FilesDownloadHelper(); + FileDownloadHelper downloadHelper = new FileDownloadHelper(); downloadHelper.downloadFile(user, file); } diff --git a/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java b/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java index a7f10ffac956..24887f50587e 100644 --- a/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java +++ b/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java @@ -307,7 +307,7 @@ private boolean hasServerChange(Document document) throws FileNotFoundException /** * Updates the OC File after a successful download. * - * TODO unify with code from {@link com.nextcloud.client.files.downloader.FilesDownloadWorker} and {@link DownloadTask}. + * TODO unify with code from {@link com.nextcloud.client.files.downloader.FileDownloadWorker} and {@link DownloadTask}. */ private void saveDownloadedFile(FileDataStorageManager storageManager, DownloadFileOperation dfo, OCFile file) { long syncDate = System.currentTimeMillis(); diff --git a/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java b/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java index 18329af5dc5d..c91702076d5b 100644 --- a/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java +++ b/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java @@ -28,7 +28,7 @@ import android.util.Pair; import com.nextcloud.client.account.User; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.IndexedForest; import com.owncloud.android.lib.common.OwnCloudAccount; @@ -169,9 +169,9 @@ public void cancel(Account account, OCFile file){ * this is a fast and ugly patch. */ private void sendBroadcastNewSyncFolder(Account account, String remotePath) { - Intent added = new Intent(FilesDownloadWorker.Companion.getDownloadAddedMessage()); - added.putExtra(FilesDownloadWorker.ACCOUNT_NAME, account.name); - added.putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, remotePath); + Intent added = new Intent(FileDownloadWorker.Companion.getDownloadAddedMessage()); + added.putExtra(FileDownloadWorker.ACCOUNT_NAME, account.name); + added.putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, remotePath); added.setPackage(mService.getPackageName()); LocalBroadcastManager.getInstance(mService.getApplicationContext()).sendBroadcast(added); } @@ -182,10 +182,10 @@ private void sendBroadcastNewSyncFolder(Account account, String remotePath) { */ private void sendBroadcastFinishedSyncFolder(Account account, String remotePath, boolean success) { - Intent finished = new Intent(FilesDownloadWorker.Companion.getDownloadFinishMessage()); - finished.putExtra(FilesDownloadWorker.ACCOUNT_NAME, account.name); - finished.putExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH, remotePath); - finished.putExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, success); + Intent finished = new Intent(FileDownloadWorker.Companion.getDownloadFinishMessage()); + finished.putExtra(FileDownloadWorker.ACCOUNT_NAME, account.name); + finished.putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, remotePath); + finished.putExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, success); finished.setPackage(mService.getPackageName()); LocalBroadcastManager.getInstance(mService.getApplicationContext()).sendBroadcast(finished); } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java index 9ae88f3c7248..48cc4986a99e 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java @@ -20,7 +20,7 @@ package com.owncloud.android.ui.activity; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.services.OperationsService.OperationsServiceBinder; @@ -32,7 +32,7 @@ public interface ComponentsGetter { * To be invoked when the parent activity is fully created to get a reference * to the FileDownloadWorker. */ - public FilesDownloadWorker.FileDownloaderBinder getFileDownloaderBinder(); + public FileDownloadWorker.FileDownloaderBinder getFileDownloaderBinder(); /** diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt index 5d18e9698380..0a1f8d3bffbe 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt @@ -21,7 +21,7 @@ import android.content.Intent import android.os.Bundle import android.widget.Toast import com.nextcloud.client.account.User -import com.nextcloud.client.files.downloader.FilesDownloadHelper +import com.nextcloud.client.files.downloader.FileDownloadHelper import com.nextcloud.model.HTTPStatusCodes import com.nextcloud.utils.extensions.getParcelableArgument import com.owncloud.android.R @@ -115,7 +115,7 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener Decision.KEEP_SERVER -> if (!shouldDeleteLocal()) { // Overwrite local file file?.let { - FilesDownloadHelper().downloadFile( + FileDownloadHelper().downloadFile( getUser().orElseThrow { RuntimeException() }, file, conflictUploadId diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index e36c0e9ed2ca..f0c1573cc293 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -43,8 +43,8 @@ import com.google.android.material.snackbar.Snackbar; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; -import com.nextcloud.client.files.downloader.FilesDownloadHelper; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadHelper; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.utils.EditorUtils; @@ -166,7 +166,7 @@ public abstract class FileActivity extends DrawerActivity private boolean mResumed; - protected FilesDownloadWorker.FileDownloaderBinder mDownloaderBinder; + protected FileDownloadWorker.FileDownloaderBinder mDownloaderBinder; protected FileUploaderBinder mUploaderBinder; private ServiceConnection mUploadServiceConnection; @@ -234,7 +234,7 @@ protected void onCreate(Bundle savedInstanceState) { Context.BIND_AUTO_CREATE); if (user != null) { - new FilesDownloadHelper().downloadFile(user, mFile); + new FileDownloadHelper().downloadFile(user, mFile); } mUploadServiceConnection = newTransferenceServiceConnection(); @@ -612,7 +612,7 @@ public void onServiceDisconnected(ComponentName component) { } @Override - public FilesDownloadWorker.FileDownloaderBinder getFileDownloaderBinder() { + public FileDownloadWorker.FileDownloaderBinder getFileDownloaderBinder() { return mDownloaderBinder; } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 7e110b45a2c9..5b757c5a88d1 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -65,8 +65,8 @@ import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; import com.nextcloud.client.files.DeepLinkHandler; -import com.nextcloud.client.files.downloader.FilesDownloadHelper; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadHelper; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.media.PlayerServiceConnection; import com.nextcloud.client.network.ClientFactory; import com.nextcloud.client.network.ConnectivityService; @@ -685,12 +685,12 @@ protected void refreshDetailsFragmentIfVisible(String downloadEvent, String down // the user browsed to other file ; forget the automatic preview mWaitingToPreview = null; - } else if (downloadEvent.equals(FilesDownloadWorker.Companion.getDownloadAddedMessage())) { + } else if (downloadEvent.equals(FileDownloadWorker.Companion.getDownloadAddedMessage())) { // grant that the details fragment updates the progress bar detailsFragment.listenForTransferProgress(); detailsFragment.updateFileDetails(true, false); - } else if (downloadEvent.equals(FilesDownloadWorker.Companion.getDownloadFinishMessage())) { + } else if (downloadEvent.equals(FileDownloadWorker.Companion.getDownloadFinishMessage())) { // update the details panel boolean detailsFragmentChanged = false; if (waitedPreview) { @@ -1116,8 +1116,8 @@ protected void onResume() { localBroadcastManager.registerReceiver(mUploadFinishReceiver, uploadIntentFilter); // Listen for download messages - IntentFilter downloadIntentFilter = new IntentFilter(FilesDownloadWorker.Companion.getDownloadAddedMessage()); - downloadIntentFilter.addAction(FilesDownloadWorker.Companion.getDownloadFinishMessage()); + IntentFilter downloadIntentFilter = new IntentFilter(FileDownloadWorker.Companion.getDownloadAddedMessage()); + downloadIntentFilter.addAction(FileDownloadWorker.Companion.getDownloadFinishMessage()); mDownloadFinishReceiver = new DownloadFinishReceiver(); localBroadcastManager.registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); @@ -1418,7 +1418,7 @@ private boolean isAscendant(String linkedToRemotePath) { /** - * Class waiting for broadcast events from the {@link FilesDownloadWorker} service. + * Class waiting for broadcast events from the {@link FileDownloadWorker} service. *

* Updates the UI when a download is started or finished, provided that it is relevant for the current folder. */ @@ -1427,16 +1427,16 @@ private class DownloadFinishReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { boolean sameAccount = isSameAccount(intent); - String downloadedRemotePath = intent.getStringExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH); + String downloadedRemotePath = intent.getStringExtra(FileDownloadWorker.EXTRA_REMOTE_PATH); String downloadBehaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); boolean isDescendant = isDescendant(downloadedRemotePath); if (sameAccount && isDescendant) { - String linkedToRemotePath = intent.getStringExtra(FilesDownloadWorker.EXTRA_LINKED_TO_PATH); + String linkedToRemotePath = intent.getStringExtra(FileDownloadWorker.EXTRA_LINKED_TO_PATH); if (linkedToRemotePath == null || isAscendant(linkedToRemotePath)) { updateListOfFilesFragment(false); } - refreshDetailsFragmentIfVisible(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, false)); + refreshDetailsFragmentIfVisible(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, false)); } if (mWaitingToSend != null) { @@ -1469,7 +1469,7 @@ private boolean isAscendant(String linkedToRemotePath) { } private boolean isSameAccount(Intent intent) { - String accountName = intent.getStringExtra(FilesDownloadWorker.ACCOUNT_NAME); + String accountName = intent.getStringExtra(FileDownloadWorker.ACCOUNT_NAME); return accountName != null && getAccount() != null && accountName.equals(getAccount().name); } } @@ -1571,9 +1571,9 @@ private class ListServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { - if (component.equals(new ComponentName(FileDisplayActivity.this, FilesDownloadWorker.class))) { + if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloadWorker.class))) { Log_OC.d(TAG, "Download service connected"); - mDownloaderBinder = (FilesDownloadWorker.FileDownloaderBinder) service; + mDownloaderBinder = (FileDownloadWorker.FileDownloaderBinder) service; if (mWaitingToPreview != null && getStorageManager() != null) { // update the file mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); @@ -1604,7 +1604,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { - if (component.equals(new ComponentName(FileDisplayActivity.this, FilesDownloadWorker.class))) { + if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloadWorker.class))) { Log_OC.d(TAG, "Download service disconnected"); mDownloaderBinder = null; } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { @@ -1886,7 +1886,7 @@ private void requestForDownload() { User user = getUser().orElseThrow(RuntimeException::new); //if (!mWaitingToPreview.isDownloading()) { if (!mDownloaderBinder.isDownloading(user, mWaitingToPreview)) { - new FilesDownloadHelper().downloadFile(user, mWaitingToPreview); + new FileDownloadHelper().downloadFile(user, mWaitingToPreview); } } @@ -1958,7 +1958,7 @@ public void run() { private void requestForDownload(OCFile file, String downloadBehaviour, String packageName, String activityName) { final User currentUser = getUser().orElseThrow(RuntimeException::new); if (!mDownloaderBinder.isDownloading(currentUser, mWaitingToPreview)) { - new FilesDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); + new FileDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 24622e11414a..b0d200277393 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -41,7 +41,7 @@ import com.google.common.collect.Sets; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.onboarding.FirstRunActivity; import com.nextcloud.java.util.Optional; @@ -525,8 +525,8 @@ private class ManageAccountsServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { - if (component.equals(new ComponentName(ManageAccountsActivity.this, FilesDownloadWorker.class))) { - mDownloaderBinder = (FilesDownloadWorker.FileDownloaderBinder) service; + if (component.equals(new ComponentName(ManageAccountsActivity.this, FileDownloadWorker.class))) { + mDownloaderBinder = (FileDownloadWorker.FileDownloaderBinder) service; } else if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service connected"); @@ -536,7 +536,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { - if (component.equals(new ComponentName(ManageAccountsActivity.this, FilesDownloadWorker.class))) { + if (component.equals(new ComponentName(ManageAccountsActivity.this, FileDownloadWorker.class))) { Log_OC.d(TAG, "Download service suddenly disconnected"); mDownloaderBinder = null; } else if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 9f16f82dd003..45bebf359d68 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -44,7 +44,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ClientFactory; import com.nextcloud.client.network.ConnectivityService; @@ -502,7 +502,7 @@ public void updateFileDetails(OCFile file, User user) { * TODO Remove parameter when the transferring state of files is kept in database. * * @param transferring Flag signaling if the file should be considered as downloading or uploading, although - * {@link com.nextcloud.client.files.downloader.FilesDownloadWorker.FileDownloaderBinder#isDownloading(User, OCFile)} and + * {@link com.nextcloud.client.files.downloader.FileDownloadWorker.FileDownloaderBinder#isDownloading(User, OCFile)} and * {@link FileUploaderBinder#isUploading(User, OCFile)} return false. * @param refresh If 'true', try to refresh the whole file from the database */ @@ -534,7 +534,7 @@ public void updateFileDetails(boolean transferring, boolean refresh) { setFavoriteIconStatus(file.isFavorite()); // configure UI for depending upon local state of the file - FilesDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); + FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(user, file)) @@ -659,7 +659,7 @@ private void setButtonsForTransferring() { // show the progress bar for the transfer binding.progressBlock.setVisibility(View.VISIBLE); binding.progressText.setVisibility(View.VISIBLE); - FilesDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); + FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); //if (getFile().isDownloading()) { if (downloaderBinder != null && downloaderBinder.isDownloading(user, getFile())) { diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 8700a80c61f1..08e7416512bf 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -47,7 +47,7 @@ import com.nextcloud.client.account.CurrentAccountProvider; import com.nextcloud.client.account.User; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.java.util.Optional; @@ -997,7 +997,7 @@ public void cancelTransference(OCFile file) { } // for both files and folders - FilesDownloadWorker.FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder(); + FileDownloadWorker.FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder(); if (downloaderBinder != null && downloaderBinder.isDownloading(currentUser, file)) { downloaderBinder.cancelPendingOrCurrentDownloads(currentUser.toPlatformAccount(), file); } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index fe11f92933fc..13363d231fd2 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -37,8 +37,8 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; -import com.nextcloud.client.files.downloader.FilesDownloadHelper; -import com.nextcloud.client.files.downloader.FilesDownloadWorker; +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.utils.extensions.IntentExtensionsKt; @@ -311,8 +311,8 @@ private class PreviewImageServiceConnection implements ServiceConnection { public void onServiceConnected(ComponentName component, IBinder service) { if (component.equals(new ComponentName(PreviewImageActivity.this, - FilesDownloadWorker.class))) { - mDownloaderBinder = (FilesDownloadWorker.FileDownloaderBinder) service; + FileDownloadWorker.class))) { + mDownloaderBinder = (FileDownloadWorker.FileDownloaderBinder) service; if (mRequestWaitingForBinder) { mRequestWaitingForBinder = false; Log_OC.d(TAG, "Simulating reselection of current page after connection " + @@ -331,7 +331,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { if (component.equals(new ComponentName(PreviewImageActivity.this, - FilesDownloadWorker.class))) { + FileDownloadWorker.class))) { Log_OC.d(TAG, "Download service suddenly disconnected"); mDownloaderBinder = null; } else if (component.equals(new ComponentName(PreviewImageActivity.this, @@ -359,7 +359,7 @@ protected void onResume() { super.onResume(); mDownloadFinishReceiver = new DownloadFinishReceiver(); - IntentFilter downloadIntentFilter = new IntentFilter(FilesDownloadWorker.Companion.getDownloadFinishMessage()); + IntentFilter downloadIntentFilter = new IntentFilter(FileDownloadWorker.Companion.getDownloadFinishMessage()); localBroadcastManager.registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); mUploadFinishReceiver = new UploadFinishReceiver(); @@ -413,7 +413,7 @@ public void requestForDownload(OCFile file, String downloadBehaviour) { } else if (!mDownloaderBinder.isDownloading(getUserAccountManager().getUser(), file)) { final User user = getUser().orElseThrow(RuntimeException::new); - new FilesDownloadHelper().downloadFile(user, file, downloadBehaviour); + new FileDownloadHelper().downloadFile(user, file, downloadBehaviour); } } @@ -478,7 +478,7 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse } /** - * Class waiting for broadcast events from the {@link FilesDownloadWorker} service. + * Class waiting for broadcast events from the {@link FileDownloadWorker} service. * * Updates the UI when a download is started or finished, provided that it is relevant for the * folder displayed in the gallery. @@ -498,12 +498,12 @@ public void onReceive(Context context, Intent intent) { } private void previewNewImage(Intent intent) { - String accountName = intent.getStringExtra(FilesDownloadWorker.ACCOUNT_NAME); - String downloadedRemotePath = intent.getStringExtra(FilesDownloadWorker.EXTRA_REMOTE_PATH); + String accountName = intent.getStringExtra(FileDownloadWorker.ACCOUNT_NAME); + String downloadedRemotePath = intent.getStringExtra(FileDownloadWorker.EXTRA_REMOTE_PATH); String downloadBehaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); if (getAccount().name.equals(accountName) && downloadedRemotePath != null) { OCFile file = getStorageManager().getFileByPath(downloadedRemotePath); - boolean downloadWasFine = intent.getBooleanExtra(FilesDownloadWorker.EXTRA_DOWNLOAD_RESULT, false); + boolean downloadWasFine = intent.getBooleanExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, false); if (EditImageActivity.OPEN_IMAGE_EDITOR.equals(downloadBehaviour)) { startImageEditor(file); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index d42ebb0255cc..d4a1bd18c154 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -53,7 +53,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; -import com.nextcloud.client.files.downloader.FilesDownloadHelper; +import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.media.ExoplayerListener; import com.nextcloud.client.media.NextcloudExoPlayer; @@ -479,7 +479,7 @@ public void onFileActionChosen(final int itemId) { backgroundJobManager); } else if (itemId == R.id.action_download_file) { if (!containerActivity.getFileDownloaderBinder().isDownloading(user, getFile())) { - new FilesDownloadHelper().downloadFile(user, getFile()); + new FileDownloadHelper().downloadFile(user, getFile()); } } } From 67f8d2620a41c7c2fc8f0a2dedd2116c0d28f877 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 27 Dec 2023 09:58:27 +0100 Subject: [PATCH 115/189] Fix createMockTask test Signed-off-by: alperozturk --- .../nextcloud/client/files/downloader/TransferManagerTest.kt | 2 +- .../com/nextcloud/client/files/downloader/DownloadTask.kt | 4 +++- .../nextcloud/client/files/transfer/TransferManagerImpl.kt | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt b/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt index ef5e692d8084..39cdf9c02ebd 100644 --- a/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt +++ b/app/src/androidTest/java/com/nextcloud/client/files/downloader/TransferManagerTest.kt @@ -107,7 +107,7 @@ class TransferManagerTest { private fun createMockTask(): DownloadTask { val task = mockk() - every { task.download(any()) } answers { + every { task.download(any(), any(), any()) } answers { taskProgress.forEach { arg>(1).invoke(it) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadTask.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadTask.kt index 46a1d2e590f7..dda1816864e7 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadTask.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadTask.kt @@ -21,6 +21,7 @@ package com.nextcloud.client.files.downloader import android.content.ContentResolver import android.content.Context +import com.nextcloud.client.core.IsCancelled import com.nextcloud.client.files.DownloadRequest import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -62,7 +63,8 @@ class DownloadTask( } } - fun download(request: DownloadRequest): Result { + // Unused progress, isCancelled arguments needed for TransferManagerTest + fun download(request: DownloadRequest, progress: (Int) -> Unit, isCancelled: IsCancelled): Result { val op = DownloadFileOperation(request.user, request.file, context) val client = clientProvider.invoke() val result = op.execute(client) diff --git a/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerImpl.kt b/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerImpl.kt index 8ff6fa24822d..0113002d96d3 100644 --- a/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/files/transfer/TransferManagerImpl.kt @@ -138,8 +138,8 @@ class TransferManagerImpl( } } else { val downloadTask = downloadTaskFactory.create() - val wrapper: TaskFunction = { _: ((Int) -> Unit), _ -> - downloadTask.download(request) + val wrapper: TaskFunction = { progress: ((Int) -> Unit), isCancelled -> + downloadTask.download(request, progress, isCancelled) } wrapper } From 362bf803010d4aec342657f3d2d8b129b640e0bc Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 27 Dec 2023 14:49:26 +0100 Subject: [PATCH 116/189] Fix Notifications Signed-off-by: alperozturk --- .../files/downloader/FileDownloadWorker.kt | 32 +++++----- .../download/DownloadNotificationManager.kt | 58 +++++++++++-------- 2 files changed, 50 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 65afdab5f26c..48bbc217b94f 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -152,6 +152,7 @@ class FileDownloadWorker( context, downloadType ) + operation.addDatatransferProgressListener(this) operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder) val putResult = pendingDownloads.putIfAbsent( @@ -232,9 +233,11 @@ class FileDownloadWorker( private fun notifyDownloadStart(download: DownloadFileOperation) { lastPercent = 0 - notificationManager.notifyForStart(download) - notificationManager.setContentIntent(intents.detailsIntent(download), PendingIntent.FLAG_IMMUTABLE) - notificationManager.showDownloadInProgressNotification() + notificationManager.run { + notifyForStart(download) + setContentIntent(intents.detailsIntent(download), PendingIntent.FLAG_IMMUTABLE) + showDownloadInProgressNotification() + } } private fun getOCAccountForDownload(): OwnCloudAccount { @@ -285,25 +288,24 @@ class FileDownloadWorker( download: DownloadFileOperation, downloadResult: RemoteOperationResult<*> ) { - if (downloadResult.isCancelled) { - return - } + dismissDownloadInProgressNotification() - if (downloadResult.isSuccess) { - dismissDownloadInProgressNotification() + if (downloadResult.isCancelled) { return } val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) - notificationManager.prepareForResult(downloadResult, needsToUpdateCredentials) + notificationManager.run { + prepareForResult(downloadResult, needsToUpdateCredentials) - if (needsToUpdateCredentials) { - notificationManager.setCredentialContentIntent(download.user) - } else { - notificationManager.setContentIntent(intents.detailsIntent(null), PendingIntent.FLAG_IMMUTABLE) - } + if (needsToUpdateCredentials) { + setCredentialContentIntent(download.user) + } else { + setContentIntent(intents.detailsIntent(null), PendingIntent.FLAG_IMMUTABLE) + } - notificationManager.notifyForResult(downloadResult, download) + notifyForResult(downloadResult, download) + } } private fun dismissDownloadInProgressNotification() { diff --git a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt index 0bd056e19cbb..63c9731b046d 100644 --- a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt @@ -83,41 +83,49 @@ class DownloadNotificationManager(private val context: Context, private val view @Suppress("MagicNumber") fun notifyForResult(result: RemoteOperationResult<*>, download: DownloadFileOperation) { - val errorMessage = ErrorMessageAdapter.getErrorCauseMessage( - result, - download, - context.resources - ) - - notificationBuilder.setContentText(errorMessage) - - notificationManager.notify(SecureRandom().nextInt(), notificationBuilder.build()) + val tickerId = getTickerId(result.isSuccess, null) + val notifyId = SecureRandom().nextInt() - if (result.isSuccess) { - NotificationUtils.cancelWithDelay( - notificationManager, - R.string.downloader_download_succeeded_ticker, - 2000 + val contentText = if (result.isSuccess) { + context.getString(R.string.downloader_download_succeeded_ticker) + } else { + ErrorMessageAdapter.getErrorCauseMessage( + result, + download, + context.resources ) } + + notificationBuilder.run { + setTicker(context.getString(tickerId)) + setContentText(contentText) + notificationManager.notify(notifyId, this.build()) + } + + NotificationUtils.cancelWithDelay( + notificationManager, + notifyId, + 2000 + ) } - fun prepareForResult( - downloadResult: RemoteOperationResult<*>, - needsToUpdateCredentials: Boolean - ) { - var tickerId = - if (downloadResult.isSuccess) { + private fun getTickerId(isSuccess: Boolean, needsToUpdateCredentials: Boolean?): Int { + return if (needsToUpdateCredentials == true) { + R.string.downloader_download_failed_credentials_error + } else { + if (isSuccess) { R.string.downloader_download_succeeded_ticker } else { R.string.downloader_download_failed_ticker } - - tickerId = if (needsToUpdateCredentials) { - R.string.downloader_download_failed_credentials_error - } else { - tickerId } + } + + fun prepareForResult( + downloadResult: RemoteOperationResult<*>, + needsToUpdateCredentials: Boolean + ) { + val tickerId = getTickerId(downloadResult.isSuccess, needsToUpdateCredentials) notificationBuilder .setTicker(context.getString(tickerId)) From a7f3b088786cddd0e64c5bd625bbb58e3193b598 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 27 Dec 2023 14:50:41 +0100 Subject: [PATCH 117/189] Add TODO for some unknown code block Signed-off-by: alperozturk --- .../com/nextcloud/client/files/downloader/FileDownloadWorker.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 48bbc217b94f..3db6196dceda 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -309,6 +309,7 @@ class FileDownloadWorker( } private fun dismissDownloadInProgressNotification() { + // TODO Check necessity of this function call conflictUploadId?.let { if (it > 0) { uploadsStorageManager.removeUpload(it) From 8ab218869da5c72b027ef45bb6ad0450e2caa607 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 27 Dec 2023 14:54:40 +0100 Subject: [PATCH 118/189] Add TODO for some unknown code block Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadWorker.kt | 8 ++++++-- .../notifications/download/DownloadNotificationManager.kt | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 3db6196dceda..6e1ef43431cd 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -288,12 +288,16 @@ class FileDownloadWorker( download: DownloadFileOperation, downloadResult: RemoteOperationResult<*> ) { - dismissDownloadInProgressNotification() - if (downloadResult.isCancelled) { return } + // TODO Check why we calling only for success? + if (downloadResult.isSuccess) { + dismissDownloadInProgressNotification() + return + } + val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) notificationManager.run { prepareForResult(downloadResult, needsToUpdateCredentials) diff --git a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt index 63c9731b046d..51bace7e6728 100644 --- a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt @@ -83,6 +83,8 @@ class DownloadNotificationManager(private val context: Context, private val view @Suppress("MagicNumber") fun notifyForResult(result: RemoteOperationResult<*>, download: DownloadFileOperation) { + dismissDownloadInProgressNotification() + val tickerId = getTickerId(result.isSuccess, null) val notifyId = SecureRandom().nextInt() From 72da838c005461982fc7bff51276b2a5ac2d3a6f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 27 Dec 2023 14:57:59 +0100 Subject: [PATCH 119/189] Remove return Signed-off-by: alperozturk --- .../com/nextcloud/client/files/downloader/FileDownloadWorker.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 6e1ef43431cd..1bdc1ff3518e 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -295,7 +295,6 @@ class FileDownloadWorker( // TODO Check why we calling only for success? if (downloadResult.isSuccess) { dismissDownloadInProgressNotification() - return } val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) From 987b943edd1b064f1683aacd0982dfb0c5fbe05b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 27 Dec 2023 15:47:48 +0100 Subject: [PATCH 120/189] Fix sync Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 24 +++++-- .../client/jobs/BackgroundJobManager.kt | 13 ++++ .../client/jobs/BackgroundJobManagerImpl.kt | 72 +++++++++++++++++-- .../SynchronizeFolderOperation.java | 16 +---- 4 files changed, 102 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index bd8b8417d9ea..ecbe944a9af3 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -31,6 +31,7 @@ import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType import com.owncloud.android.utils.MimeTypeUtil import java.io.File +import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject class FileDownloadHelper { @@ -79,8 +80,21 @@ class FileDownloadHelper { storageManager?.saveConflict(file, null) } - fun downloadFile(user: User, ocFile: OCFile) { + fun downloadFiles(user: User, ocFile: List, cancelRequest: AtomicBoolean) { backgroundJobManager.startFilesDownloadJob( + user, + ocFile, + "", + DownloadType.DOWNLOAD, + "", + "", + null, + cancelRequest + ) + } + + fun downloadFile(user: User, ocFile: OCFile) { + backgroundJobManager.startFileDownloadJob( user, ocFile, "", @@ -92,7 +106,7 @@ class FileDownloadHelper { } fun downloadFile(user: User, ocFile: OCFile, behaviour: String) { - backgroundJobManager.startFilesDownloadJob( + backgroundJobManager.startFileDownloadJob( user, ocFile, behaviour, @@ -104,7 +118,7 @@ class FileDownloadHelper { } fun downloadFile(user: User, ocFile: OCFile, downloadType: DownloadType) { - backgroundJobManager.startFilesDownloadJob( + backgroundJobManager.startFileDownloadJob( user, ocFile, "", @@ -116,7 +130,7 @@ class FileDownloadHelper { } fun downloadFile(user: User, ocFile: OCFile, conflictUploadId: Long) { - backgroundJobManager.startFilesDownloadJob( + backgroundJobManager.startFileDownloadJob( user, ocFile, "", @@ -137,7 +151,7 @@ class FileDownloadHelper { packageName: String, conflictUploadId: Long? ) { - backgroundJobManager.startFilesDownloadJob( + backgroundJobManager.startFileDownloadJob( user, ocFile, behaviour, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 30b90d1fbe18..4b2f505c8d3f 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -24,6 +24,7 @@ import androidx.work.ListenableWorker import com.nextcloud.client.account.User import com.owncloud.android.datamodel.OCFile import com.owncloud.android.operations.DownloadType +import java.util.concurrent.atomic.AtomicBoolean /** * This interface allows to control, schedule and monitor all application @@ -147,6 +148,18 @@ interface BackgroundJobManager { @Suppress("LongParameterList") fun startFilesDownloadJob( + user: User, + files: List, + behaviour: String, + downloadType: DownloadType?, + activityName: String, + packageName: String, + conflictUploadId: Long?, + cancelRequest: AtomicBoolean + ) + + @Suppress("LongParameterList") + fun startFileDownloadJob( user: User, ocFile: OCFile, behaviour: String, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 8e815432c97a..98d67a1c04df 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -42,10 +42,12 @@ import com.nextcloud.client.documentscan.GeneratePdfFromImagesWork import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.client.preferences.AppPreferences import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.lib.common.operations.OperationCancelledException import com.owncloud.android.operations.DownloadType import java.util.Date import java.util.UUID import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicBoolean import kotlin.reflect.KClass /** @@ -509,20 +511,20 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_FILES_UPLOAD + user.accountName, ExistingWorkPolicy.KEEP, request) } - override fun startFilesDownloadJob( + private fun getOneTimeDownloadRequest( user: User, - ocFile: OCFile, + file: OCFile, behaviour: String, downloadType: DownloadType?, activityName: String, packageName: String, conflictUploadId: Long? - ) { + ): OneTimeWorkRequest { val gson = Gson() val data = workDataOf( FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FILE to gson.toJson(ocFile), + FileDownloadWorker.FILE to gson.toJson(file), FileDownloadWorker.BEHAVIOUR to behaviour, FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), FileDownloadWorker.ACTIVITY_NAME to activityName, @@ -530,9 +532,69 @@ internal class BackgroundJobManagerImpl( FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId ) - val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) + return oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .setInputData(data) .build() + } + + @Throws(OperationCancelledException::class) + override fun startFilesDownloadJob( + user: User, + files: List, + behaviour: String, + downloadType: DownloadType?, + activityName: String, + packageName: String, + conflictUploadId: Long?, + cancelRequest: AtomicBoolean + ) { + val workRequestList = mutableListOf() + + for (file in files) { + synchronized(cancelRequest) { + if (cancelRequest.get()) { + throw OperationCancelledException() + } + + workRequestList.add( + getOneTimeDownloadRequest( + user, + file, + behaviour, + downloadType, + activityName, + packageName, + conflictUploadId + ) + ) + } + } + + val chain = workManager + .beginWith(workRequestList.first()) + .then(workRequestList.subList(1, workRequestList.size)) + + chain.enqueue() + } + + override fun startFileDownloadJob( + user: User, + ocFile: OCFile, + behaviour: String, + downloadType: DownloadType?, + activityName: String, + packageName: String, + conflictUploadId: Long? + ) { + val request = getOneTimeDownloadRequest( + user, + ocFile, + behaviour, + downloadType, + activityName, + packageName, + conflictUploadId + ) workManager.enqueueUniqueWork(JOB_FILES_DOWNLOAD + user.accountName, ExistingWorkPolicy.REPLACE, request) } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index cf60dacea912..e69a96821b2f 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -444,19 +444,9 @@ private void syncContents() throws OperationCancelledException { startContentSynchronizations(mFilesToSyncContents); } - - private void startDirectDownloads() throws OperationCancelledException { - for (OCFile file : mFilesForDirectDownload) { - synchronized(mCancellationRequested) { - if (mCancellationRequested.get()) { - throw new OperationCancelledException(); - } - - FileDownloadHelper downloadHelper = new FileDownloadHelper(); - - downloadHelper.downloadFile(user, file); - } - } + private void startDirectDownloads() { + FileDownloadHelper downloadHelper = new FileDownloadHelper(); + downloadHelper.downloadFiles(user, mFilesForDirectDownload, mCancellationRequested); } /** From f8050dca09f9d3793b76dbd6400d221e315d711c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 27 Dec 2023 15:57:34 +0100 Subject: [PATCH 121/189] Fix Code Analytics Signed-off-by: alperozturk --- .../java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 98d67a1c04df..9ce6b3a85d63 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -511,6 +511,7 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_FILES_UPLOAD + user.accountName, ExistingWorkPolicy.KEEP, request) } + @Suppress("LongParameterList") private fun getOneTimeDownloadRequest( user: User, file: OCFile, From ad0ce0edb31de9a4d9e547e1f8e5d2d59cd6e34b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 12:56:31 +0100 Subject: [PATCH 122/189] Rebase master Signed-off-by: alperozturk --- .../android/files/FileMenuFilterIT.kt | 2 +- .../files/downloader/FileDownloadWorker.kt | 31 +++++++------------ .../utils/extensions/ContextExtensions.kt | 31 +++++++++++++++++++ .../android/files/FileMenuFilter.java | 2 +- .../ui/activity/FileDisplayActivity.java | 5 ++- .../android/ui/adapter/OCFileListDelegate.kt | 31 +++++++------------ .../ui/fragment/FileDetailFragment.java | 4 +-- .../ui/helpers/FileOperationsHelper.java | 4 +-- .../ui/preview/PreviewImageActivity.java | 2 +- .../ui/preview/PreviewMediaFragment.java | 2 +- 10 files changed, 63 insertions(+), 51 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt index 5e48d0b9647d..0b7f37bdcee1 100644 --- a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt @@ -77,7 +77,7 @@ class FileMenuFilterIT : AbstractIT() { MockKAnnotations.init(this) every { mockFileUploaderBinder.isUploading(any(), any()) } returns false every { mockComponentsGetter.fileUploaderBinder } returns mockFileUploaderBinder - every { mockFileDownloaderBinder.isDownloading(any(), any()) } returns false + every { mockFileDownloaderBinder.isDownloading() } returns false every { mockComponentsGetter.fileDownloaderBinder } returns mockFileDownloaderBinder every { mockOperationsServiceBinder.isSynchronizing(any(), any()) } returns false every { mockComponentsGetter.operationsServiceBinder } returns mockOperationsServiceBinder diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 1bdc1ff3518e..26fb514d5569 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -28,15 +28,17 @@ import android.app.PendingIntent import android.content.Context import android.os.Binder import android.os.IBinder -import android.util.Pair import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters import com.google.gson.Gson import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.jobs.BackgroundJobManagerImpl.Companion.JOB_FILES_DOWNLOAD import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional +import com.nextcloud.utils.extensions.cancelWork +import com.nextcloud.utils.extensions.isWorkScheduled import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager @@ -338,8 +340,10 @@ class FileDownloadWorker( val percent: Int = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt() if (percent != lastPercent) { - notificationManager.updateDownloadProgressNotification(filePath, percent, totalToTransfer) - notificationManager.showDownloadInProgressNotification() + notificationManager.run { + updateDownloadProgressNotification(filePath, percent, totalToTransfer) + showDownloadInProgressNotification() + } } lastPercent = percent @@ -348,21 +352,8 @@ class FileDownloadWorker( inner class FileDownloaderBinder : Binder(), OnDatatransferProgressListener { private val boundListeners: MutableMap = HashMap() - fun cancelPendingOrCurrentDownloads(account: Account, file: OCFile) { - val removeResult: Pair = - pendingDownloads.remove(account.name, file.remotePath) - val download = removeResult.first - - if (download != null) { - download.cancel() - } else { - if (currentUser?.isPresent == true && - currentDownload?.remotePath?.startsWith(file.remotePath) == true && - account.name == currentUser.get()?.accountName - ) { - currentDownload?.cancel() - } - } + fun cancelPendingOrCurrentDownloads() { + context.cancelWork(JOB_FILES_DOWNLOAD) } fun cancelAllDownloadsForAccount(accountName: String?) { @@ -373,8 +364,8 @@ class FileDownloadWorker( cancelPendingDownloads(accountName) } - fun isDownloading(user: User?, file: OCFile?): Boolean { - return user != null && file != null && pendingDownloads.contains(user.accountName, file.remotePath) + fun isDownloading(): Boolean { + return context.isWorkScheduled(JOB_FILES_DOWNLOAD) } fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt index 6dc7dde71e2f..35527d4af8b1 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt @@ -27,7 +27,12 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.Build +import androidx.work.WorkInfo +import androidx.work.WorkManager +import com.google.common.util.concurrent.ListenableFuture import com.owncloud.android.datamodel.ReceiverFlag +import com.owncloud.android.lib.common.utils.Log_OC +import java.util.concurrent.ExecutionException @SuppressLint("UnspecifiedRegisterReceiverFlag") fun Context.registerBroadcastReceiver(receiver: BroadcastReceiver?, filter: IntentFilter, flag: ReceiverFlag): Intent? { @@ -37,3 +42,29 @@ fun Context.registerBroadcastReceiver(receiver: BroadcastReceiver?, filter: Inte registerReceiver(receiver, filter) } } + +fun Context.isWorkScheduled(tag: String): Boolean { + val instance = WorkManager.getInstance(this) + val statuses: ListenableFuture> = instance.getWorkInfosByTag(tag) + var running = false + var workInfoList: List = emptyList() + + try { + workInfoList = statuses.get() + } catch (e: ExecutionException) { + Log_OC.d("Worker", "ExecutionException in isWorkScheduled: $e") + } catch (e: InterruptedException) { + Log_OC.d("Worker", "InterruptedException in isWorkScheduled: $e") + } + + for (workInfo in workInfoList) { + val state = workInfo.state + running = running || (state == WorkInfo.State.RUNNING || state == WorkInfo.State.ENQUEUED) + } + + return running +} + +fun Context.cancelWork(tag: String) { + WorkManager.getInstance(this).cancelAllWorkByTag(tag) +} diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index f3da5e4b807c..b5e721e4a99f 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -402,7 +402,7 @@ private boolean anyFileDownloading(FileDownloadWorker.FileDownloaderBinder downl boolean downloading = false; if (downloaderBinder != null) { for (Iterator iterator = files.iterator(); !downloading && iterator.hasNext(); ) { - downloading = downloaderBinder.isDownloading(user, iterator.next()); + downloading = downloaderBinder.isDownloading(); } } return downloading; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 5b757c5a88d1..5be55acdd3fb 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1884,8 +1884,7 @@ public void onTransferStateChanged(OCFile file, boolean downloading, boolean upl private void requestForDownload() { User user = getUser().orElseThrow(RuntimeException::new); - //if (!mWaitingToPreview.isDownloading()) { - if (!mDownloaderBinder.isDownloading(user, mWaitingToPreview)) { + if (!mDownloaderBinder.isDownloading()) { new FileDownloadHelper().downloadFile(user, mWaitingToPreview); } } @@ -1957,7 +1956,7 @@ public void run() { private void requestForDownload(OCFile file, String downloadBehaviour, String packageName, String activityName) { final User currentUser = getUser().orElseThrow(RuntimeException::new); - if (!mDownloaderBinder.isDownloading(currentUser, mWaitingToPreview)) { + if (!mDownloaderBinder.isDownloading()) { new FileDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 82413ce9076b..4be366f9afd8 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -32,7 +32,6 @@ import androidx.core.content.res.ResourcesCompat import com.elyeproj.loaderviewlibrary.LoaderImageView 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.utils.extensions.createRoundedOutline import com.owncloud.android.R @@ -341,33 +340,25 @@ class OCFileListDelegate( private fun showLocalFileIndicator(file: OCFile, gridViewHolder: ListGridImageViewHolder) { val operationsServiceBinder = transferServiceGetter.operationsServiceBinder + val fileDownloaderBinder = transferServiceGetter.fileDownloaderBinder val fileUploaderBinder = transferServiceGetter.fileUploaderBinder - - val icon: Int? = when { + when { operationsServiceBinder?.isSynchronizing(user, file) == true || - FileDownloadHelper.instance().isDownloading(user, file) || + fileDownloaderBinder?.isDownloading() == true || fileUploaderBinder?.isUploading(user, file) == true -> { // synchronizing, downloading or uploading - R.drawable.ic_synchronizing + gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing) + gridViewHolder.localFileIndicator.visibility = View.VISIBLE } - file.etagInConflict != null -> { - R.drawable.ic_synchronizing_error + // conflict + gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing_error) + gridViewHolder.localFileIndicator.visibility = View.VISIBLE } - file.isDown -> { - R.drawable.ic_synced - } - - else -> { - null - } - } - - gridViewHolder.localFileIndicator.run { - icon?.let { - setImageResource(icon) - visibility = View.VISIBLE + // downloaded + gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synced) + gridViewHolder.localFileIndicator.visibility = View.VISIBLE } } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 45bebf359d68..a152511bb231 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -537,7 +537,7 @@ public void updateFileDetails(boolean transferring, boolean refresh) { FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); if (transferring - || (downloaderBinder != null && downloaderBinder.isDownloading(user, file)) + || (downloaderBinder != null && downloaderBinder.isDownloading()) || (uploaderBinder != null && uploaderBinder.isUploading(user, file))) { setButtonsForTransferring(); @@ -662,7 +662,7 @@ private void setButtonsForTransferring() { FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); //if (getFile().isDownloading()) { - if (downloaderBinder != null && downloaderBinder.isDownloading(user, getFile())) { + if (downloaderBinder != null && downloaderBinder.isDownloading()) { binding.progressText.setText(R.string.downloader_download_in_progress_ticker); } else { if (uploaderBinder != null && uploaderBinder.isUploading(user, getFile())) { diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 08e7416512bf..f6876116a1d2 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -998,8 +998,8 @@ public void cancelTransference(OCFile file) { // for both files and folders FileDownloadWorker.FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder(); - if (downloaderBinder != null && downloaderBinder.isDownloading(currentUser, file)) { - downloaderBinder.cancelPendingOrCurrentDownloads(currentUser.toPlatformAccount(), file); + if (downloaderBinder != null && downloaderBinder.isDownloading()) { + downloaderBinder.cancelPendingOrCurrentDownloads(); } FileUploaderBinder uploaderBinder = fileActivity.getFileUploaderBinder(); if (uploaderBinder != null && uploaderBinder.isUploading(currentUser, file)) { diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 13363d231fd2..9bba853ff241 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -411,7 +411,7 @@ public void requestForDownload(OCFile file, String downloadBehaviour) { if (mDownloaderBinder == null) { Log_OC.d(TAG, "requestForDownload called without binder to download service"); - } else if (!mDownloaderBinder.isDownloading(getUserAccountManager().getUser(), file)) { + } else if (!mDownloaderBinder.isDownloading()) { final User user = getUser().orElseThrow(RuntimeException::new); new FileDownloadHelper().downloadFile(user, file, downloadBehaviour); } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index d4a1bd18c154..8c2c5d02b54a 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -478,7 +478,7 @@ public void onFileActionChosen(final int itemId) { getView(), backgroundJobManager); } else if (itemId == R.id.action_download_file) { - if (!containerActivity.getFileDownloaderBinder().isDownloading(user, getFile())) { + if (!containerActivity.getFileDownloaderBinder().isDownloading()) { new FileDownloadHelper().downloadFile(user, getFile()); } } From 02f9b66fe91322f09c6820404c3b4153cb760ea1 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 28 Dec 2023 09:54:03 +0100 Subject: [PATCH 123/189] Fix FileDownloaderBinder cancelAllDownloadsForAccount Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadWorker.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 26fb514d5569..94824ee90a0a 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -155,8 +155,8 @@ class FileDownloadWorker( downloadType ) - operation.addDatatransferProgressListener(this) - operation.addDatatransferProgressListener(downloadBinder as FileDownloaderBinder) + operation.addDownloadDataTransferProgressListener(this) + operation.addDownloadDataTransferProgressListener(downloadBinder as FileDownloaderBinder) val putResult = pendingDownloads.putIfAbsent( user?.accountName, file.remotePath, @@ -203,7 +203,7 @@ class FileDownloadWorker( val isAccountExist = accountManager.exists(currentDownload?.user?.toPlatformAccount()) if (!isAccountExist) { - cancelPendingDownloads(currentDownload?.user?.accountName) + removePendingDownload(currentDownload?.user?.accountName) return } @@ -228,7 +228,7 @@ class FileDownloadWorker( } } - private fun cancelPendingDownloads(accountName: String?) { + private fun removePendingDownload(accountName: String?) { pendingDownloads.remove(accountName) } @@ -358,10 +358,11 @@ class FileDownloadWorker( fun cancelAllDownloadsForAccount(accountName: String?) { if (currentDownload?.user?.nameEquals(accountName) == true) { + context.cancelWork(JOB_FILES_DOWNLOAD) currentDownload?.cancel() } - cancelPendingDownloads(accountName) + removePendingDownload(accountName) } fun isDownloading(): Boolean { From 74a4271b009276814a7e76954e016ba9899d67d1 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 28 Dec 2023 10:20:56 +0100 Subject: [PATCH 124/189] Use BackgroundJobManager for cancel Downloads Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadWorker.kt | 11 ++++++----- .../com/nextcloud/client/jobs/BackgroundJobManager.kt | 2 ++ .../nextcloud/client/jobs/BackgroundJobManagerImpl.kt | 4 ++++ .../nextcloud/utils/extensions/ContextExtensions.kt | 4 ---- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 94824ee90a0a..46b5e22c8365 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -37,7 +37,6 @@ import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.jobs.BackgroundJobManagerImpl.Companion.JOB_FILES_DOWNLOAD import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional -import com.nextcloud.utils.extensions.cancelWork import com.nextcloud.utils.extensions.isWorkScheduled import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -353,13 +352,15 @@ class FileDownloadWorker( private val boundListeners: MutableMap = HashMap() fun cancelPendingOrCurrentDownloads() { - context.cancelWork(JOB_FILES_DOWNLOAD) + helper.backgroundJobManager.cancelFilesDownloadJob(currentUser.get()) } fun cancelAllDownloadsForAccount(accountName: String?) { - if (currentDownload?.user?.nameEquals(accountName) == true) { - context.cancelWork(JOB_FILES_DOWNLOAD) - currentDownload?.cancel() + currentDownload?.user?.let { + if (it.nameEquals(accountName)) { + helper.backgroundJobManager.cancelFilesDownloadJob(it) + currentDownload?.cancel() + } } removePendingDownload(accountName) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 4b2f505c8d3f..7223ab067c2b 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -146,6 +146,8 @@ interface BackgroundJobManager { fun getFileUploads(user: User): LiveData> fun cancelFilesUploadJob(user: User) + fun cancelFilesDownloadJob(user: User) + @Suppress("LongParameterList") fun startFilesDownloadJob( user: User, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 9ce6b3a85d63..ff2a7fa8941e 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -609,6 +609,10 @@ internal class BackgroundJobManagerImpl( workManager.cancelJob(JOB_FILES_UPLOAD, user) } + override fun cancelFilesDownloadJob(user: User) { + workManager.cancelJob(JOB_FILES_DOWNLOAD, user) + } + override fun startPdfGenerateAndUploadWork( user: User, uploadFolder: String, diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt index 35527d4af8b1..613599ae06e3 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt @@ -64,7 +64,3 @@ fun Context.isWorkScheduled(tag: String): Boolean { return running } - -fun Context.cancelWork(tag: String) { - WorkManager.getInstance(this).cancelAllWorkByTag(tag) -} From ce77997033dc23a6bc26abc34b6ae4a37cfa958c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 09:05:33 +0100 Subject: [PATCH 125/189] Rebase master Signed-off-by: alperozturk --- .../android/files/FileMenuFilterIT.kt | 2 +- .../files/downloader/FileDownloadWorker.kt | 10 ++++---- .../client/jobs/BackgroundJobManager.kt | 2 ++ .../client/jobs/BackgroundJobManagerImpl.kt | 12 +++++++++- .../utils/extensions/ContextExtensions.kt | 24 +------------------ .../android/files/FileMenuFilter.java | 3 ++- .../ui/activity/FileDisplayActivity.java | 4 ++-- .../android/ui/adapter/OCFileListDelegate.kt | 2 +- .../ui/fragment/FileDetailFragment.java | 5 ++-- .../ui/helpers/FileOperationsHelper.java | 2 +- .../ui/preview/PreviewImageActivity.java | 6 ++--- .../ui/preview/PreviewMediaFragment.java | 2 +- 12 files changed, 33 insertions(+), 41 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt index 0b7f37bdcee1..5e48d0b9647d 100644 --- a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt @@ -77,7 +77,7 @@ class FileMenuFilterIT : AbstractIT() { MockKAnnotations.init(this) every { mockFileUploaderBinder.isUploading(any(), any()) } returns false every { mockComponentsGetter.fileUploaderBinder } returns mockFileUploaderBinder - every { mockFileDownloaderBinder.isDownloading() } returns false + every { mockFileDownloaderBinder.isDownloading(any(), any()) } returns false every { mockComponentsGetter.fileDownloaderBinder } returns mockFileDownloaderBinder every { mockOperationsServiceBinder.isSynchronizing(any(), any()) } returns false every { mockComponentsGetter.operationsServiceBinder } returns mockOperationsServiceBinder diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 46b5e22c8365..84d6bfaa24e5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -34,10 +34,8 @@ import androidx.work.WorkerParameters import com.google.gson.Gson import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager -import com.nextcloud.client.jobs.BackgroundJobManagerImpl.Companion.JOB_FILES_DOWNLOAD import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional -import com.nextcloud.utils.extensions.isWorkScheduled import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager @@ -122,6 +120,7 @@ class FileDownloadWorker( } } + // FIXME not returning multiple string for folder private fun getRequestDownloads(): AbstractList { conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) @@ -366,8 +365,11 @@ class FileDownloadWorker( removePendingDownload(accountName) } - fun isDownloading(): Boolean { - return context.isWorkScheduled(JOB_FILES_DOWNLOAD) + fun isDownloading(user: User?, file: OCFile?): Boolean { + return user != null && file != null && helper.backgroundJobManager.isStartFileDownloadJobScheduled( + user, + file + ) } fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 7223ab067c2b..1f3bc87057a8 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -148,6 +148,8 @@ interface BackgroundJobManager { fun cancelFilesDownloadJob(user: User) + fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean + @Suppress("LongParameterList") fun startFilesDownloadJob( user: User, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index ff2a7fa8941e..491f03dfc690 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -41,6 +41,7 @@ import com.nextcloud.client.di.Injectable 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.OCFile import com.owncloud.android.lib.common.operations.OperationCancelledException import com.owncloud.android.operations.DownloadType @@ -538,6 +539,14 @@ internal class BackgroundJobManagerImpl( .build() } + private fun startFileDownloadJobTag(user: User, file: OCFile): String { + return JOB_FILES_DOWNLOAD + user.accountName + file.fileId + } + + override fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean { + return workManager.isWorkScheduled(startFileDownloadJobTag(user, file)) + } + @Throws(OperationCancelledException::class) override fun startFilesDownloadJob( user: User, @@ -597,7 +606,8 @@ internal class BackgroundJobManagerImpl( conflictUploadId ) - workManager.enqueueUniqueWork(JOB_FILES_DOWNLOAD + user.accountName, ExistingWorkPolicy.REPLACE, request) + val tag = startFileDownloadJobTag(user, ocFile) + workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) } override fun getFileUploads(user: User): LiveData> { diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt index 613599ae06e3..ee0b30e2ad0e 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt @@ -27,12 +27,8 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.Build -import androidx.work.WorkInfo import androidx.work.WorkManager -import com.google.common.util.concurrent.ListenableFuture import com.owncloud.android.datamodel.ReceiverFlag -import com.owncloud.android.lib.common.utils.Log_OC -import java.util.concurrent.ExecutionException @SuppressLint("UnspecifiedRegisterReceiverFlag") fun Context.registerBroadcastReceiver(receiver: BroadcastReceiver?, filter: IntentFilter, flag: ReceiverFlag): Intent? { @@ -44,23 +40,5 @@ fun Context.registerBroadcastReceiver(receiver: BroadcastReceiver?, filter: Inte } fun Context.isWorkScheduled(tag: String): Boolean { - val instance = WorkManager.getInstance(this) - val statuses: ListenableFuture> = instance.getWorkInfosByTag(tag) - var running = false - var workInfoList: List = emptyList() - - try { - workInfoList = statuses.get() - } catch (e: ExecutionException) { - Log_OC.d("Worker", "ExecutionException in isWorkScheduled: $e") - } catch (e: InterruptedException) { - Log_OC.d("Worker", "InterruptedException in isWorkScheduled: $e") - } - - for (workInfo in workInfoList) { - val state = workInfo.state - running = running || (state == WorkInfo.State.RUNNING || state == WorkInfo.State.ENQUEUED) - } - - return running + return WorkManager.getInstance(this).isWorkScheduled(tag) } diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index b5e721e4a99f..83c1db654425 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -400,9 +400,10 @@ private boolean anyFileSynchronizing(OperationsServiceBinder opsBinder) { private boolean anyFileDownloading(FileDownloadWorker.FileDownloaderBinder downloaderBinder) { boolean downloading = false; + if (downloaderBinder != null) { for (Iterator iterator = files.iterator(); !downloading && iterator.hasNext(); ) { - downloading = downloaderBinder.isDownloading(); + downloading = downloaderBinder.isDownloading(user, iterator.next()); } } return downloading; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 5be55acdd3fb..3f42beeca9dc 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1884,7 +1884,7 @@ public void onTransferStateChanged(OCFile file, boolean downloading, boolean upl private void requestForDownload() { User user = getUser().orElseThrow(RuntimeException::new); - if (!mDownloaderBinder.isDownloading()) { + if (!mDownloaderBinder.isDownloading(user, mWaitingToPreview)) { new FileDownloadHelper().downloadFile(user, mWaitingToPreview); } } @@ -1956,7 +1956,7 @@ public void run() { private void requestForDownload(OCFile file, String downloadBehaviour, String packageName, String activityName) { final User currentUser = getUser().orElseThrow(RuntimeException::new); - if (!mDownloaderBinder.isDownloading()) { + if (!mDownloaderBinder.isDownloading(currentUser, file)) { new FileDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 4be366f9afd8..e350d8b7c856 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -344,7 +344,7 @@ class OCFileListDelegate( val fileUploaderBinder = transferServiceGetter.fileUploaderBinder when { operationsServiceBinder?.isSynchronizing(user, file) == true || - fileDownloaderBinder?.isDownloading() == true || + fileDownloaderBinder?.isDownloading(user, file) == true || fileUploaderBinder?.isUploading(user, file) == true -> { // synchronizing, downloading or uploading gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index a152511bb231..2091fa90fe44 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -537,7 +537,7 @@ public void updateFileDetails(boolean transferring, boolean refresh) { FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); if (transferring - || (downloaderBinder != null && downloaderBinder.isDownloading()) + || (downloaderBinder != null && downloaderBinder.isDownloading(user, file)) || (uploaderBinder != null && uploaderBinder.isUploading(user, file))) { setButtonsForTransferring(); @@ -661,8 +661,7 @@ private void setButtonsForTransferring() { binding.progressText.setVisibility(View.VISIBLE); FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); - //if (getFile().isDownloading()) { - if (downloaderBinder != null && downloaderBinder.isDownloading()) { + if (downloaderBinder != null && downloaderBinder.isDownloading(user, getFile())) { binding.progressText.setText(R.string.downloader_download_in_progress_ticker); } else { if (uploaderBinder != null && uploaderBinder.isUploading(user, getFile())) { diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index f6876116a1d2..80dd92aa1ca3 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -998,7 +998,7 @@ public void cancelTransference(OCFile file) { // for both files and folders FileDownloadWorker.FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder(); - if (downloaderBinder != null && downloaderBinder.isDownloading()) { + if (downloaderBinder != null && downloaderBinder.isDownloading(currentUser, file)) { downloaderBinder.cancelPendingOrCurrentDownloads(); } FileUploaderBinder uploaderBinder = fileActivity.getFileUploaderBinder(); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 9bba853ff241..352f4edf47fe 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -408,11 +408,11 @@ public void requestForDownload(OCFile file) { } public void requestForDownload(OCFile file, String downloadBehaviour) { + final User user = getUser().orElseThrow(RuntimeException::new); + if (mDownloaderBinder == null) { Log_OC.d(TAG, "requestForDownload called without binder to download service"); - - } else if (!mDownloaderBinder.isDownloading()) { - final User user = getUser().orElseThrow(RuntimeException::new); + } else if (!mDownloaderBinder.isDownloading(user, file)) { new FileDownloadHelper().downloadFile(user, file, downloadBehaviour); } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index 8c2c5d02b54a..d4a1bd18c154 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -478,7 +478,7 @@ public void onFileActionChosen(final int itemId) { getView(), backgroundJobManager); } else if (itemId == R.id.action_download_file) { - if (!containerActivity.getFileDownloaderBinder().isDownloading()) { + if (!containerActivity.getFileDownloaderBinder().isDownloading(user, getFile())) { new FileDownloadHelper().downloadFile(user, getFile()); } } From 285e6ac8ed4bcc938622b08cbc89734f8a802cd8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 09:05:52 +0100 Subject: [PATCH 126/189] Rebase master Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 13 ------ .../files/downloader/FileDownloadWorker.kt | 2 + .../client/jobs/BackgroundJobManager.kt | 12 ------ .../client/jobs/BackgroundJobManagerImpl.kt | 42 ------------------- .../SynchronizeFolderOperation.java | 12 +++++- 5 files changed, 12 insertions(+), 69 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index ecbe944a9af3..35288eb166f2 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -80,19 +80,6 @@ class FileDownloadHelper { storageManager?.saveConflict(file, null) } - fun downloadFiles(user: User, ocFile: List, cancelRequest: AtomicBoolean) { - backgroundJobManager.startFilesDownloadJob( - user, - ocFile, - "", - DownloadType.DOWNLOAD, - "", - "", - null, - cancelRequest - ) - } - fun downloadFile(user: User, ocFile: OCFile) { backgroundJobManager.startFileDownloadJob( user, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 84d6bfaa24e5..336557ba98d2 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -34,8 +34,10 @@ import androidx.work.WorkerParameters import com.google.gson.Gson import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.jobs.BackgroundJobManagerImpl.Companion.JOB_FILES_DOWNLOAD import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional +import com.nextcloud.utils.extensions.isWorkScheduled import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 1f3bc87057a8..f7263265742f 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -150,18 +150,6 @@ interface BackgroundJobManager { fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean - @Suppress("LongParameterList") - fun startFilesDownloadJob( - user: User, - files: List, - behaviour: String, - downloadType: DownloadType?, - activityName: String, - packageName: String, - conflictUploadId: Long?, - cancelRequest: AtomicBoolean - ) - @Suppress("LongParameterList") fun startFileDownloadJob( user: User, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 491f03dfc690..79234a8ec81b 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -43,12 +43,10 @@ import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.utils.extensions.isWorkScheduled import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.lib.common.operations.OperationCancelledException import com.owncloud.android.operations.DownloadType import java.util.Date import java.util.UUID import java.util.concurrent.TimeUnit -import java.util.concurrent.atomic.AtomicBoolean import kotlin.reflect.KClass /** @@ -547,46 +545,6 @@ internal class BackgroundJobManagerImpl( return workManager.isWorkScheduled(startFileDownloadJobTag(user, file)) } - @Throws(OperationCancelledException::class) - override fun startFilesDownloadJob( - user: User, - files: List, - behaviour: String, - downloadType: DownloadType?, - activityName: String, - packageName: String, - conflictUploadId: Long?, - cancelRequest: AtomicBoolean - ) { - val workRequestList = mutableListOf() - - for (file in files) { - synchronized(cancelRequest) { - if (cancelRequest.get()) { - throw OperationCancelledException() - } - - workRequestList.add( - getOneTimeDownloadRequest( - user, - file, - behaviour, - downloadType, - activityName, - packageName, - conflictUploadId - ) - ) - } - } - - val chain = workManager - .beginWith(workRequestList.first()) - .then(workRequestList.subList(1, workRequestList.size)) - - chain.enqueue() - } - override fun startFileDownloadJob( user: User, ocFile: OCFile, diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index e69a96821b2f..0cb9cff609e8 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -444,9 +444,17 @@ private void syncContents() throws OperationCancelledException { startContentSynchronizations(mFilesToSyncContents); } - private void startDirectDownloads() { + private void startDirectDownloads() throws OperationCancelledException { FileDownloadHelper downloadHelper = new FileDownloadHelper(); - downloadHelper.downloadFiles(user, mFilesForDirectDownload, mCancellationRequested); + + for (OCFile file : mFilesForDirectDownload) { + synchronized(mCancellationRequested) { + if (mCancellationRequested.get()) { + throw new OperationCancelledException(); + } + downloadHelper.downloadFile(user, file); + } + } } /** From 43e187b7194cced76dab526c100b846b17c3fd5d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 28 Dec 2023 15:20:57 +0100 Subject: [PATCH 127/189] Fix requestDownloads Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadWorker.kt | 10 ++++------ .../android/ui/activity/FileDisplayActivity.java | 5 +++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 336557ba98d2..0fa8963261a9 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -34,10 +34,8 @@ import androidx.work.WorkerParameters import com.google.gson.Gson import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager -import com.nextcloud.client.jobs.BackgroundJobManagerImpl.Companion.JOB_FILES_DOWNLOAD import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional -import com.nextcloud.utils.extensions.isWorkScheduled import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager @@ -122,7 +120,6 @@ class FileDownloadWorker( } } - // FIXME not returning multiple string for folder private fun getRequestDownloads(): AbstractList { conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) @@ -144,7 +141,7 @@ class FileDownloadWorker( val requestedDownloads: AbstractList = Vector() - try { + return try { val operation = DownloadFileOperation( user, file, @@ -168,11 +165,12 @@ class FileDownloadWorker( requestedDownloads.add(downloadKey) localBroadcastManager.sendBroadcast(intents.newDownloadIntent(operation, putResult.second)) } + + requestedDownloads } catch (e: IllegalArgumentException) { Log_OC.e(TAG, "Not enough information provided in intent: " + e.message) + requestedDownloads } - - return requestedDownloads } private fun addAccountUpdateListener() { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 3f42beeca9dc..dfdc51293033 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1587,6 +1587,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { } else { return; } + // a new chance to get the mDownloadBinder through // getFileDownloadBinder() - THIS IS A MESS OCFileListFragment listOfFiles = getListOfFilesFragment(); @@ -1594,9 +1595,9 @@ public void onServiceConnected(ComponentName component, IBinder service) { IntentExtensionsKt.getParcelableArgument(getIntent(), EXTRA_FILE, OCFile.class) == null))) { listOfFiles.listDirectory(MainApp.isOnlyOnDevice(), false); } + Fragment leftFragment = getLeftFragment(); - if (leftFragment instanceof FileDetailFragment) { - FileDetailFragment detailFragment = (FileDetailFragment) leftFragment; + if (leftFragment instanceof FileDetailFragment detailFragment) { detailFragment.listenForTransferProgress(); detailFragment.updateFileDetails(false, false); } From e1cc14fd8b9614729cfa9536f21ac84eb7af1af8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 28 Dec 2023 15:55:33 +0100 Subject: [PATCH 128/189] Fix kotlin spotless check Signed-off-by: alperozturk --- .../com/nextcloud/client/files/downloader/FileDownloadHelper.kt | 1 - .../main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 35288eb166f2..cb53a4db9f4d 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -31,7 +31,6 @@ import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType import com.owncloud.android.utils.MimeTypeUtil import java.io.File -import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject class FileDownloadHelper { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index f7263265742f..f3488a222f94 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -24,7 +24,6 @@ import androidx.work.ListenableWorker import com.nextcloud.client.account.User import com.owncloud.android.datamodel.OCFile import com.owncloud.android.operations.DownloadType -import java.util.concurrent.atomic.AtomicBoolean /** * This interface allows to control, schedule and monitor all application From d2ea1e466643c951cb6c2152d5e2075caa121de5 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 12:56:41 +0100 Subject: [PATCH 129/189] Rebase master Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 19 ++++++++++++ .../files/downloader/FileDownloadWorker.kt | 9 ++++-- .../client/jobs/BackgroundJobManager.kt | 2 +- .../client/jobs/BackgroundJobManagerImpl.kt | 4 +-- .../download/DownloadNotificationManager.kt | 2 +- .../android/files/FileMenuFilter.java | 18 +++++------ .../android/ui/activity/FileActivity.java | 1 + .../ui/activity/FileDisplayActivity.java | 9 +++--- .../android/ui/adapter/OCFileListDelegate.kt | 5 +-- .../ui/fragment/FileDetailFragment.java | 11 ++++--- .../ui/helpers/FileOperationsHelper.java | 1 + .../ui/preview/PreviewImageActivity.java | 6 ++-- .../ui/preview/PreviewMediaActivity.kt | 31 ++++++++++++++++--- .../ui/preview/PreviewMediaFragment.java | 5 +-- 14 files changed, 87 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index cb53a4db9f4d..c9c17bf6dca5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -45,6 +45,13 @@ class FileDownloadHelper { MainApp.getAppComponent().inject(this) } + fun isDownloading(user: User?, file: OCFile?): Boolean { + return user != null && file != null && backgroundJobManager.isStartFileDownloadJobScheduled( + user, + file + ) + } + fun saveFile( file: OCFile, currentDownload: DownloadFileOperation?, @@ -103,6 +110,18 @@ class FileDownloadHelper { ) } + fun downloadFile(user: User, ocFile: OCFile, behaviour: String, packageName: String, activityName: String) { + backgroundJobManager.startFileDownloadJob( + user, + ocFile, + behaviour, + DownloadType.DOWNLOAD, + packageName, + packageName, + null + ) + } + fun downloadFile(user: User, ocFile: OCFile, downloadType: DownloadType) { backgroundJobManager.startFileDownloadJob( user, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 0fa8963261a9..e8b1e1104580 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -351,13 +351,18 @@ class FileDownloadWorker( private val boundListeners: MutableMap = HashMap() fun cancelPendingOrCurrentDownloads() { - helper.backgroundJobManager.cancelFilesDownloadJob(currentUser.get()) + currentDownload?.file?.let { file -> + helper.backgroundJobManager.cancelFilesDownloadJob(currentUser.get(), file) + } } fun cancelAllDownloadsForAccount(accountName: String?) { currentDownload?.user?.let { if (it.nameEquals(accountName)) { - helper.backgroundJobManager.cancelFilesDownloadJob(it) + currentDownload?.file?.let { file -> + helper.backgroundJobManager.cancelFilesDownloadJob(it, file) + } + currentDownload?.cancel() } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index f3488a222f94..ee338476397f 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -145,7 +145,7 @@ interface BackgroundJobManager { fun getFileUploads(user: User): LiveData> fun cancelFilesUploadJob(user: User) - fun cancelFilesDownloadJob(user: User) + fun cancelFilesDownloadJob(user: User, file: OCFile) fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 79234a8ec81b..11a2ab765a25 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -577,8 +577,8 @@ internal class BackgroundJobManagerImpl( workManager.cancelJob(JOB_FILES_UPLOAD, user) } - override fun cancelFilesDownloadJob(user: User) { - workManager.cancelJob(JOB_FILES_DOWNLOAD, user) + override fun cancelFilesDownloadJob(user: User, file: OCFile) { + workManager.cancelAllWorkByTag(startFileDownloadJobTag(user, file)) } override fun startPdfGenerateAndUploadWork( diff --git a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt index 51bace7e6728..f15896692b6d 100644 --- a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt @@ -89,7 +89,7 @@ class DownloadNotificationManager(private val context: Context, private val view val notifyId = SecureRandom().nextInt() val contentText = if (result.isSuccess) { - context.getString(R.string.downloader_download_succeeded_ticker) + download.file.fileName + " " + context.getString(R.string.downloader_download_succeeded_ticker) } else { ErrorMessageAdapter.getErrorCauseMessage( result, diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index 83c1db654425..22b942e01003 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -31,6 +31,7 @@ import com.nextcloud.android.files.FileLockingHelper; import com.nextcloud.client.account.User; import com.nextcloud.client.editimage.EditImageActivity; +import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.utils.EditorUtils; import com.owncloud.android.R; @@ -380,9 +381,9 @@ private boolean anyFileSynchronizing() { if (componentsGetter != null && !files.isEmpty() && user != null) { OperationsServiceBinder opsBinder = componentsGetter.getOperationsServiceBinder(); FileUploaderBinder uploaderBinder = componentsGetter.getFileUploaderBinder(); - FileDownloadWorker.FileDownloaderBinder downloaderBinder = componentsGetter.getFileDownloaderBinder(); + FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); synchronizing = anyFileSynchronizing(opsBinder) || // comparing local and remote - anyFileDownloading(downloaderBinder) || + anyFileDownloading(fileDownloadHelper) || anyFileUploading(uploaderBinder); } return synchronizing; @@ -398,15 +399,14 @@ private boolean anyFileSynchronizing(OperationsServiceBinder opsBinder) { return synchronizing; } - private boolean anyFileDownloading(FileDownloadWorker.FileDownloaderBinder downloaderBinder) { - boolean downloading = false; - - if (downloaderBinder != null) { - for (Iterator iterator = files.iterator(); !downloading && iterator.hasNext(); ) { - downloading = downloaderBinder.isDownloading(user, iterator.next()); + private boolean anyFileDownloading(FileDownloadHelper downloadHelper) { + for (OCFile file : files) { + if (downloadHelper.isDownloading(user, file)) { + return true; } } - return downloading; + + return false; } private boolean anyFileUploading(FileUploaderBinder uploaderBinder) { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index f0c1573cc293..11910ca5cd93 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -166,6 +166,7 @@ public abstract class FileActivity extends DrawerActivity private boolean mResumed; + protected FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); protected FileDownloadWorker.FileDownloaderBinder mDownloaderBinder; protected FileUploaderBinder mUploaderBinder; private ServiceConnection mUploadServiceConnection; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index dfdc51293033..495b54d19262 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1564,6 +1564,7 @@ protected ServiceConnection newTransferenceServiceConnection() { return new ListServiceConnection(); } + // FIXME ServiceConnection will not trigger anymore /** * Defines callbacks for service binding, passed to bindService() */ @@ -1885,8 +1886,8 @@ public void onTransferStateChanged(OCFile file, boolean downloading, boolean upl private void requestForDownload() { User user = getUser().orElseThrow(RuntimeException::new); - if (!mDownloaderBinder.isDownloading(user, mWaitingToPreview)) { - new FileDownloadHelper().downloadFile(user, mWaitingToPreview); + if (!fileDownloadHelper.isDownloading(user, mWaitingToPreview)) { + fileDownloadHelper.downloadFile(user, mWaitingToPreview); } } @@ -1957,8 +1958,8 @@ public void run() { private void requestForDownload(OCFile file, String downloadBehaviour, String packageName, String activityName) { final User currentUser = getUser().orElseThrow(RuntimeException::new); - if (!mDownloaderBinder.isDownloading(currentUser, file)) { - new FileDownloadHelper().downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); + if (!fileDownloadHelper.isDownloading(currentUser, file)) { + fileDownloadHelper.downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index e350d8b7c856..5cd63ffe60c8 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -32,6 +32,7 @@ import androidx.core.content.res.ResourcesCompat import com.elyeproj.loaderviewlibrary.LoaderImageView 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.utils.extensions.createRoundedOutline import com.owncloud.android.R @@ -340,11 +341,11 @@ class OCFileListDelegate( private fun showLocalFileIndicator(file: OCFile, gridViewHolder: ListGridImageViewHolder) { val operationsServiceBinder = transferServiceGetter.operationsServiceBinder - val fileDownloaderBinder = transferServiceGetter.fileDownloaderBinder + val fileDownloadHelper = FileDownloadHelper() val fileUploaderBinder = transferServiceGetter.fileUploaderBinder when { operationsServiceBinder?.isSynchronizing(user, file) == true || - fileDownloaderBinder?.isDownloading(user, file) == true || + fileDownloadHelper.isDownloading(user, file) || fileUploaderBinder?.isUploading(user, file) == true -> { // synchronizing, downloading or uploading gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 2091fa90fe44..55c9f6700798 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -44,6 +44,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; +import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ClientFactory; @@ -502,7 +503,7 @@ public void updateFileDetails(OCFile file, User user) { * TODO Remove parameter when the transferring state of files is kept in database. * * @param transferring Flag signaling if the file should be considered as downloading or uploading, although - * {@link com.nextcloud.client.files.downloader.FileDownloadWorker.FileDownloaderBinder#isDownloading(User, OCFile)} and + * {@link FileDownloadHelper#isDownloading(User, OCFile)} and * {@link FileUploaderBinder#isUploading(User, OCFile)} return false. * @param refresh If 'true', try to refresh the whole file from the database */ @@ -534,10 +535,10 @@ public void updateFileDetails(boolean transferring, boolean refresh) { setFavoriteIconStatus(file.isFavorite()); // configure UI for depending upon local state of the file - FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); + FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); if (transferring - || (downloaderBinder != null && downloaderBinder.isDownloading(user, file)) + || (fileDownloadHelper.isDownloading(user, file)) || (uploaderBinder != null && uploaderBinder.isUploading(user, file))) { setButtonsForTransferring(); @@ -659,9 +660,9 @@ private void setButtonsForTransferring() { // show the progress bar for the transfer binding.progressBlock.setVisibility(View.VISIBLE); binding.progressText.setVisibility(View.VISIBLE); - FileDownloadWorker.FileDownloaderBinder downloaderBinder = containerActivity.getFileDownloaderBinder(); + FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); - if (downloaderBinder != null && downloaderBinder.isDownloading(user, getFile())) { + if (fileDownloadHelper.isDownloading(user, getFile())) { binding.progressText.setText(R.string.downloader_download_in_progress_ticker); } else { if (uploaderBinder != null && uploaderBinder.isUploading(user, getFile())) { diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 80dd92aa1ca3..d6cb6f325597 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -47,6 +47,7 @@ import com.nextcloud.client.account.CurrentAccountProvider; import com.nextcloud.client.account.User; +import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ConnectivityService; diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 352f4edf47fe..aacea713eb58 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -410,10 +410,8 @@ public void requestForDownload(OCFile file) { public void requestForDownload(OCFile file, String downloadBehaviour) { final User user = getUser().orElseThrow(RuntimeException::new); - if (mDownloaderBinder == null) { - Log_OC.d(TAG, "requestForDownload called without binder to download service"); - } else if (!mDownloaderBinder.isDownloading(user, file)) { - new FileDownloadHelper().downloadFile(user, file, downloadBehaviour); + if (!fileDownloadHelper.isDownloading(user, file)) { + fileDownloadHelper.downloadFile(user, file, downloadBehaviour); } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt index 23d7bd00b40f..8de694773eed 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt @@ -27,7 +27,9 @@ package com.owncloud.android.ui.preview import android.app.Activity +import android.content.ComponentName import android.content.Intent +import android.content.ServiceConnection import android.content.res.Configuration import android.graphics.Bitmap import android.graphics.BitmapFactory @@ -37,6 +39,7 @@ import android.net.Uri import android.os.AsyncTask import android.os.Bundle import android.os.Handler +import android.os.IBinder import android.os.Looper import android.view.Menu import android.view.MenuItem @@ -63,6 +66,7 @@ import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.di.Injectable import com.nextcloud.client.files.downloader.FileDownloadHelper +import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.client.jobs.BackgroundJobManager import com.nextcloud.client.media.ExoplayerListener import com.nextcloud.client.media.NextcloudExoPlayer.createNextcloudExoplayer @@ -83,7 +87,6 @@ import com.owncloud.android.lib.common.operations.OnRemoteOperationListener import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC -import com.owncloud.android.operations.DownloadType import com.owncloud.android.operations.RemoveFileOperation import com.owncloud.android.operations.SynchronizeFileOperation import com.owncloud.android.ui.activity.FileActivity @@ -560,12 +563,33 @@ class PreviewMediaActivity : } } + override fun newTransferenceServiceConnection(): ServiceConnection { + return PreviewMediaServiceConnection() + } + private fun onSynchronizeFileOperationFinish(result: RemoteOperationResult<*>?) { result?.let { invalidateOptionsMenu() } } + private inner class PreviewMediaServiceConnection : ServiceConnection { + override fun onServiceConnected(componentName: ComponentName?, service: IBinder?) { + componentName?.let { + if (it == ComponentName(this@PreviewMediaActivity, FileDownloadWorker::class.java)) { + mDownloaderBinder = service as FileDownloadWorker.FileDownloaderBinder + } + } + } + + override fun onServiceDisconnected(componentName: ComponentName?) { + if (componentName == ComponentName(this@PreviewMediaActivity, FileDownloadWorker::class.java)) { + Log_OC.d(PreviewImageActivity.TAG, "Download service suddenly disconnected") + mDownloaderBinder = null + } + } + } + override fun downloadFile(file: OCFile?, packageName: String?, activityName: String?) { requestForDownload(file, OCFileListFragment.DOWNLOAD_SEND, packageName, activityName) } @@ -576,17 +600,16 @@ class PreviewMediaActivity : packageName: String? = null, activityName: String? = null ) { - if (FileDownloadHelper.instance().isDownloading(user, file)) { + if (fileDownloadHelper.isDownloading(user, file)) { return } user?.let { user -> file?.let { file -> - FileDownloadHelper.instance().downloadFile( + fileDownloadHelper.downloadFile( user, file, downloadBehavior ?: "", - DownloadType.DOWNLOAD, packageName ?: "", activityName ?: "" ) diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index d4a1bd18c154..28c3e4d4f314 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -131,6 +131,7 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene private boolean autoplay; private boolean isLivePhoto; + private final FileDownloadHelper downloadHelper = new FileDownloadHelper(); private boolean prepared; private PlayerServiceConnection mediaPlayerServiceConnection; @@ -478,8 +479,8 @@ public void onFileActionChosen(final int itemId) { getView(), backgroundJobManager); } else if (itemId == R.id.action_download_file) { - if (!containerActivity.getFileDownloaderBinder().isDownloading(user, getFile())) { - new FileDownloadHelper().downloadFile(user, getFile()); + if (!downloadHelper.isDownloading(user, getFile())) { + downloadHelper.downloadFile(user, getFile()); } } } From 24fd5587faafe6e4a8a940ac073e62a151b5d4e4 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 12:56:55 +0100 Subject: [PATCH 130/189] Rebase master Signed-off-by: alperozturk --- .../files/downloader/FileDownloadWorker.kt | 7 ++++ .../java/com/nextcloud/model/WorkerState.kt | 6 ++-- .../nextcloud/model/WorkerStateLiveData.kt | 13 +++---- .../ui/activity/FileDisplayActivity.java | 34 +++++++++++++------ 4 files changed, 40 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index e8b1e1104580..c0fb808a22bc 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -36,6 +36,8 @@ import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional +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 @@ -138,6 +140,7 @@ class FileDownloadWorker( val behaviour = inputData.keyValueMap[BEHAVIOUR] as String val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String val packageName = inputData.keyValueMap[PACKAGE_NAME] as String + setWorkerState(user, file) val requestedDownloads: AbstractList = Vector() @@ -173,6 +176,10 @@ class FileDownloadWorker( } } + private fun setWorkerState(user: User, file: OCFile) { + WorkerStateLiveData.instance?.setWorkState(WorkerState.Download(user, file)) + } + private fun addAccountUpdateListener() { val am = AccountManager.get(context) am.addOnAccountsUpdatedListener(this, null, false) diff --git a/app/src/main/java/com/nextcloud/model/WorkerState.kt b/app/src/main/java/com/nextcloud/model/WorkerState.kt index 5bca9bb62b80..1bf8a78f2847 100644 --- a/app/src/main/java/com/nextcloud/model/WorkerState.kt +++ b/app/src/main/java/com/nextcloud/model/WorkerState.kt @@ -22,9 +22,9 @@ package com.nextcloud.model import com.nextcloud.client.account.User -import com.owncloud.android.operations.DownloadFileOperation +import com.owncloud.android.datamodel.OCFile sealed class WorkerState { - object Idle : WorkerState() - class Download(var user: User?, var currentDownload: DownloadFileOperation?) : WorkerState() + object Idle + class Download(var user: User, var file: OCFile): WorkerState() } diff --git a/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt b/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt index 54fd35f4d702..8863b6dddac2 100644 --- a/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt +++ b/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt @@ -30,12 +30,13 @@ class WorkerStateLiveData private constructor() : LiveData() { } companion object { - private var instance: WorkerStateLiveData? = null - - fun instance(): WorkerStateLiveData { - return instance ?: synchronized(this) { - instance ?: WorkerStateLiveData().also { instance = it } + var instance: WorkerStateLiveData? = null + get() { + if (field == null) { + field = WorkerStateLiveData() + } + return field } - } + private set } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 495b54d19262..6635bf855926 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -73,6 +73,8 @@ import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.client.utils.IntentUtil; import com.nextcloud.java.util.Optional; +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; @@ -160,6 +162,7 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; +import androidx.lifecycle.Observer; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import kotlin.Unit; @@ -285,6 +288,7 @@ protected void onCreate(Bundle savedInstanceState) { checkStoragePath(); initSyncBroadcastReceiver(); + observeWorkerState(); } @SuppressWarnings("unchecked") @@ -1559,6 +1563,24 @@ public boolean isDrawerIndicatorAvailable() { return isRoot(getCurrentDir()); } + private void observeWorkerState() { + WorkerStateLiveData.Companion.getInstance().observe(this, state -> { + if (state instanceof WorkerState.Download) { + Log_OC.d(TAG, "Download worker started"); + handleDownloadWorkerState(); + } + }); + } + + private void handleDownloadWorkerState() { + if (mWaitingToPreview != null && getStorageManager() != null) { + mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); + if (mWaitingToPreview != null && !mWaitingToPreview.isDown()) { + requestForDownload(); + } + } + } + @Override protected ServiceConnection newTransferenceServiceConnection() { return new ListServiceConnection(); @@ -1572,17 +1594,7 @@ private class ListServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { - if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloadWorker.class))) { - Log_OC.d(TAG, "Download service connected"); - mDownloaderBinder = (FileDownloadWorker.FileDownloaderBinder) service; - if (mWaitingToPreview != null && getStorageManager() != null) { - // update the file - mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); - if (mWaitingToPreview != null && !mWaitingToPreview.isDown()) { - requestForDownload(); - } - } - } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { + if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service connected"); mUploaderBinder = (FileUploaderBinder) service; } else { From a6d3731dd3113713df8d148fef69b54dff73d828 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 10:58:40 +0100 Subject: [PATCH 131/189] Use WorkerState for handling download state Signed-off-by: alperozturk --- .../android/files/FileMenuFilterIT.kt | 6 +- .../java/com/nextcloud/test/TestActivity.kt | 2 +- .../files/downloader/FileDownloadHelper.kt | 61 ++++++++++++++++++- .../files/downloader/FileDownloadWorker.kt | 49 ++++++--------- .../download/DownloadNotificationManager.kt | 2 +- .../java/com/nextcloud/model/WorkerState.kt | 6 +- .../android/files/FileMenuFilter.java | 1 - .../android/ui/activity/ComponentsGetter.java | 4 +- .../android/ui/activity/FileActivity.java | 6 +- .../ui/activity/FileDisplayActivity.java | 4 +- .../ui/activity/ManageAccountsActivity.java | 39 +++++++----- .../ui/fragment/FileDetailFragment.java | 9 ++- .../ui/helpers/FileOperationsHelper.java | 7 +-- .../ui/preview/FileDownloadFragment.java | 8 +-- .../ui/preview/PreviewImageActivity.java | 43 +++++++------ .../ui/preview/PreviewMediaActivity.kt | 26 -------- 16 files changed, 151 insertions(+), 122 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt index 5e48d0b9647d..9c19ce243f66 100644 --- a/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/files/FileMenuFilterIT.kt @@ -62,7 +62,7 @@ class FileMenuFilterIT : AbstractIT() { private lateinit var mockFileUploaderBinder: FileUploader.FileUploaderBinder @MockK - private lateinit var mockFileDownloaderBinder: FileDownloadWorker.FileDownloaderBinder + private lateinit var mockFileDownloadProgressListener: FileDownloadWorker.FileDownloadProgressListener @MockK private lateinit var mockOperationsServiceBinder: OperationsService.OperationsServiceBinder @@ -77,8 +77,8 @@ class FileMenuFilterIT : AbstractIT() { MockKAnnotations.init(this) every { mockFileUploaderBinder.isUploading(any(), any()) } returns false every { mockComponentsGetter.fileUploaderBinder } returns mockFileUploaderBinder - every { mockFileDownloaderBinder.isDownloading(any(), any()) } returns false - every { mockComponentsGetter.fileDownloaderBinder } returns mockFileDownloaderBinder + every { mockFileDownloadProgressListener.isDownloading(any(), any()) } returns false + every { mockComponentsGetter.fileDownloadProgressListener } returns mockFileDownloadProgressListener every { mockOperationsServiceBinder.isSynchronizing(any(), any()) } returns false every { mockComponentsGetter.operationsServiceBinder } returns mockOperationsServiceBinder every { mockStorageManager.getFileById(any()) } returns OCFile("/") diff --git a/app/src/debug/java/com/nextcloud/test/TestActivity.kt b/app/src/debug/java/com/nextcloud/test/TestActivity.kt index ec98df551af0..23297a32851c 100644 --- a/app/src/debug/java/com/nextcloud/test/TestActivity.kt +++ b/app/src/debug/java/com/nextcloud/test/TestActivity.kt @@ -130,7 +130,7 @@ class TestActivity : return null } - override fun getFileDownloaderBinder(): FileDownloadWorker.FileDownloaderBinder? { + override fun getFileDownloadProgressListener(): FileDownloadWorker.FileDownloadProgressListener? { return null } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index c9c17bf6dca5..e4d7ce201ebe 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -27,13 +27,14 @@ import com.owncloud.android.MainApp import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager +import com.owncloud.android.lib.common.network.OnDatatransferProgressListener import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType import com.owncloud.android.utils.MimeTypeUtil import java.io.File import javax.inject.Inject -class FileDownloadHelper { +class FileDownloadHelper : OnDatatransferProgressListener { @Inject lateinit var backgroundJobManager: BackgroundJobManager @@ -41,10 +42,51 @@ class FileDownloadHelper { @Inject lateinit var uploadsStorageManager: UploadsStorageManager + private val boundListeners: MutableMap = HashMap() + private var currentDownload: DownloadFileOperation? = null + init { MainApp.getAppComponent().inject(this) } + fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { + if (file == null || listener == null) { + return + } + + boundListeners[file.fileId] = listener + } + + fun removeDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { + if (file == null || listener == null) { + return + } + + val fileId = file.fileId + if (boundListeners[fileId] === listener) { + boundListeners.remove(fileId) + } + } + + override fun onTransferProgress( + progressRate: Long, + totalTransferredSoFar: Long, + totalToTransfer: Long, + fileName: String + ) { + val listener = boundListeners[currentDownload?.file?.fileId] + listener?.onTransferProgress( + progressRate, + totalTransferredSoFar, + totalToTransfer, + fileName + ) + } + + fun setCurrentDownload(operation: DownloadFileOperation) { + currentDownload = operation + } + fun isDownloading(user: User?, file: OCFile?): Boolean { return user != null && file != null && backgroundJobManager.isStartFileDownloadJobScheduled( user, @@ -52,6 +94,23 @@ class FileDownloadHelper { ) } + fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { + if (user == null || file == null) return + backgroundJobManager.cancelFilesDownloadJob(user, file) + } + + fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation) { + if (currentDownload.user.nameEquals(accountName)) { + currentDownload.file?.let { file -> + backgroundJobManager.cancelFilesDownloadJob(currentDownload.user, file) + } + + currentDownload.cancel() + } + + // removePendingDownload(accountName) + } + fun saveFile( file: OCFile, currentDownload: DownloadFileOperation?, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index c0fb808a22bc..c432f253e052 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -26,8 +26,6 @@ import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener import android.app.PendingIntent import android.content.Context -import android.os.Binder -import android.os.IBinder import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters @@ -97,12 +95,13 @@ class FileDownloadWorker( private val intents = FileDownloadIntents(context) private val notificationManager = DownloadNotificationManager(context, viewThemeUtils) private val pendingDownloads = IndexedForest() - private var downloadBinder: IBinder = FileDownloaderBinder() + private var downloadProgressListener = FileDownloadProgressListener() private var currentUser = Optional.empty() private val helper = FileDownloadHelper() private var startedDownload = false private var storageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null + private var user: User? = null private val gson = Gson() @Suppress("TooGenericExceptionCaught") @@ -122,11 +121,16 @@ class FileDownloadWorker( } } + override fun onStopped() { + super.onStopped() + setIdleWorkerState() + } + private fun getRequestDownloads(): AbstractList { conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) val accountName = inputData.keyValueMap[USER_NAME] as String - val user = accountManager.getUser(accountName).get() + user = accountManager.getUser(accountName).get() val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? val downloadType = if (downloadTypeAsString != null) { if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { @@ -140,7 +144,6 @@ class FileDownloadWorker( val behaviour = inputData.keyValueMap[BEHAVIOUR] as String val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String val packageName = inputData.keyValueMap[PACKAGE_NAME] as String - setWorkerState(user, file) val requestedDownloads: AbstractList = Vector() @@ -156,7 +159,7 @@ class FileDownloadWorker( ) operation.addDownloadDataTransferProgressListener(this) - operation.addDownloadDataTransferProgressListener(downloadBinder as FileDownloaderBinder) + operation.addDownloadDataTransferProgressListener(downloadProgressListener) val putResult = pendingDownloads.putIfAbsent( user?.accountName, file.remotePath, @@ -176,10 +179,14 @@ class FileDownloadWorker( } } - private fun setWorkerState(user: User, file: OCFile) { + private fun setWorkerState(user: User?, file: DownloadFileOperation?) { WorkerStateLiveData.instance?.setWorkState(WorkerState.Download(user, file)) } + private fun setIdleWorkerState() { + WorkerStateLiveData.instance?.setWorkState(WorkerState.Idle) + } + private fun addAccountUpdateListener() { val am = AccountManager.get(context) am.addOnAccountsUpdatedListener(this, null, false) @@ -205,6 +212,7 @@ class FileDownloadWorker( if (currentDownload == null) { return } + setWorkerState(user, currentDownload) val isAccountExist = accountManager.exists(currentDownload?.user?.toPlatformAccount()) if (!isAccountExist) { @@ -354,34 +362,11 @@ class FileDownloadWorker( lastPercent = percent } - inner class FileDownloaderBinder : Binder(), OnDatatransferProgressListener { + inner class FileDownloadProgressListener : OnDatatransferProgressListener { private val boundListeners: MutableMap = HashMap() - fun cancelPendingOrCurrentDownloads() { - currentDownload?.file?.let { file -> - helper.backgroundJobManager.cancelFilesDownloadJob(currentUser.get(), file) - } - } - - fun cancelAllDownloadsForAccount(accountName: String?) { - currentDownload?.user?.let { - if (it.nameEquals(accountName)) { - currentDownload?.file?.let { file -> - helper.backgroundJobManager.cancelFilesDownloadJob(it, file) - } - - currentDownload?.cancel() - } - } - - removePendingDownload(accountName) - } - fun isDownloading(user: User?, file: OCFile?): Boolean { - return user != null && file != null && helper.backgroundJobManager.isStartFileDownloadJobScheduled( - user, - file - ) + return helper.isDownloading(user, file) } fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { diff --git a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt index f15896692b6d..2c7d4e41b4e4 100644 --- a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt @@ -89,7 +89,7 @@ class DownloadNotificationManager(private val context: Context, private val view val notifyId = SecureRandom().nextInt() val contentText = if (result.isSuccess) { - download.file.fileName + " " + context.getString(R.string.downloader_download_succeeded_ticker) + download.file.fileName } else { ErrorMessageAdapter.getErrorCauseMessage( result, diff --git a/app/src/main/java/com/nextcloud/model/WorkerState.kt b/app/src/main/java/com/nextcloud/model/WorkerState.kt index 1bf8a78f2847..5bca9bb62b80 100644 --- a/app/src/main/java/com/nextcloud/model/WorkerState.kt +++ b/app/src/main/java/com/nextcloud/model/WorkerState.kt @@ -22,9 +22,9 @@ package com.nextcloud.model import com.nextcloud.client.account.User -import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.operations.DownloadFileOperation sealed class WorkerState { - object Idle - class Download(var user: User, var file: OCFile): WorkerState() + object Idle : WorkerState() + class Download(var user: User?, var currentDownload: DownloadFileOperation?) : WorkerState() } diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index 22b942e01003..6639a201c320 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -32,7 +32,6 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.editimage.EditImageActivity; import com.nextcloud.client.files.downloader.FileDownloadHelper; -import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.utils.EditorUtils; import com.owncloud.android.R; import com.owncloud.android.datamodel.FileDataStorageManager; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java index 48cc4986a99e..0a9c2be2a19b 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ComponentsGetter.java @@ -32,9 +32,9 @@ public interface ComponentsGetter { * To be invoked when the parent activity is fully created to get a reference * to the FileDownloadWorker. */ - public FileDownloadWorker.FileDownloaderBinder getFileDownloaderBinder(); + public FileDownloadWorker.FileDownloadProgressListener getFileDownloadProgressListener(); + - /** * To be invoked when the parent activity is fully created to get a reference * to the FileUploader service API. diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index 11910ca5cd93..fb0c623fabdc 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -167,7 +167,7 @@ public abstract class FileActivity extends DrawerActivity private boolean mResumed; protected FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); - protected FileDownloadWorker.FileDownloaderBinder mDownloaderBinder; + protected FileDownloadWorker.FileDownloadProgressListener fileDownloadProgressListener; protected FileUploaderBinder mUploaderBinder; private ServiceConnection mUploadServiceConnection; @@ -613,8 +613,8 @@ public void onServiceDisconnected(ComponentName component) { } @Override - public FileDownloadWorker.FileDownloaderBinder getFileDownloaderBinder() { - return mDownloaderBinder; + public FileDownloadWorker.FileDownloadProgressListener getFileDownloadProgressListener() { + return fileDownloadProgressListener; } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 6635bf855926..a0e94413e315 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -65,7 +65,6 @@ import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; import com.nextcloud.client.files.DeepLinkHandler; -import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.media.PlayerServiceConnection; import com.nextcloud.client.network.ClientFactory; @@ -162,7 +161,6 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; -import androidx.lifecycle.Observer; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import kotlin.Unit; @@ -1620,7 +1618,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { public void onServiceDisconnected(ComponentName component) { if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloadWorker.class))) { Log_OC.d(TAG, "Download service disconnected"); - mDownloaderBinder = null; + fileDownloadProgressListener = null; } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service disconnected"); mUploaderBinder = null; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index b0d200277393..a26c4f95c13e 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -41,10 +41,11 @@ import com.google.common.collect.Sets; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; -import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.onboarding.FirstRunActivity; import com.nextcloud.java.util.Optional; +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; @@ -56,6 +57,7 @@ import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.UserInfo; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.operations.DownloadFileOperation; import com.owncloud.android.services.OperationsService; import com.owncloud.android.ui.adapter.UserListAdapter; import com.owncloud.android.ui.adapter.UserListItem; @@ -112,6 +114,9 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap private ArbitraryDataProvider arbitraryDataProvider; private boolean multipleAccountsSupported; + private String workerAccountName; + private DownloadFileOperation workerCurrentDownload; + @Inject BackgroundJobManager backgroundJobManager; @Inject UserAccountManager accountManager; @@ -159,6 +164,7 @@ protected void onCreate(Bundle savedInstanceState) { recyclerView.setAdapter(userListAdapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); initializeComponentGetters(); + observeWorkerState(); } @@ -334,9 +340,8 @@ public void run(AccountManagerFuture future) { if (mUploaderBinder != null) { mUploaderBinder.cancel(accountName); } - if (mDownloaderBinder != null) { - mDownloaderBinder.cancelAllDownloadsForAccount(accountName); - } + + fileDownloadHelper.cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); } User currentUser = getUserAccountManager().getUser(); @@ -425,9 +430,8 @@ private void performAccountRemoval(User user) { if (mUploaderBinder != null) { mUploaderBinder.cancel(user); } - if (mDownloaderBinder != null) { - mDownloaderBinder.cancelAllDownloadsForAccount(user.getAccountName()); - } + + fileDownloadHelper.cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); backgroundJobManager.startAccountRemovalJob(user.getAccountName(), false); @@ -512,6 +516,16 @@ public void onOptionItemClicked(User user, View view) { } } + private void observeWorkerState() { + WorkerStateLiveData.Companion.getInstance().observe(this, state -> { + if (state instanceof WorkerState.Download) { + Log_OC.d(TAG, "Download worker started"); + workerAccountName = ((WorkerState.Download) state).getUser().getAccountName(); + workerCurrentDownload = ((WorkerState.Download) state).getCurrentDownload(); + } + }); + } + @Override public void onAccountClicked(User user) { openAccount(user); @@ -524,11 +538,7 @@ private class ManageAccountsServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { - - if (component.equals(new ComponentName(ManageAccountsActivity.this, FileDownloadWorker.class))) { - mDownloaderBinder = (FileDownloadWorker.FileDownloaderBinder) service; - - } else if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { + if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service connected"); mUploaderBinder = (FileUploader.FileUploaderBinder) service; } @@ -536,10 +546,7 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { - if (component.equals(new ComponentName(ManageAccountsActivity.this, FileDownloadWorker.class))) { - Log_OC.d(TAG, "Download service suddenly disconnected"); - mDownloaderBinder = null; - } else if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { + if (component.equals(new ComponentName(ManageAccountsActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service suddenly disconnected"); mUploaderBinder = null; } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 55c9f6700798..1801404df9f4 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -45,7 +45,6 @@ import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.files.downloader.FileDownloadHelper; -import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ClientFactory; import com.nextcloud.client.network.ConnectivityService; @@ -694,8 +693,8 @@ private void setButtonsForRemote() { public void listenForTransferProgress() { if (progressListener != null) { - if (containerActivity.getFileDownloaderBinder() != null) { - containerActivity.getFileDownloaderBinder(). + if (containerActivity.getFileDownloadProgressListener() != null) { + containerActivity.getFileDownloadProgressListener(). addDataTransferProgressListener(progressListener, getFile()); } if (containerActivity.getFileUploaderBinder() != null) { @@ -709,8 +708,8 @@ public void listenForTransferProgress() { private void leaveTransferProgress() { if (progressListener != null) { - if (containerActivity.getFileDownloaderBinder() != null) { - containerActivity.getFileDownloaderBinder(). + if (containerActivity.getFileDownloadProgressListener() != null) { + containerActivity.getFileDownloadProgressListener(). removeDataTransferProgressListener(progressListener, getFile()); } if (containerActivity.getFileUploaderBinder() != null) { diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index d6cb6f325597..a072ddd7cd23 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -48,7 +48,6 @@ import com.nextcloud.client.account.CurrentAccountProvider; import com.nextcloud.client.account.User; import com.nextcloud.client.files.downloader.FileDownloadHelper; -import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.java.util.Optional; @@ -998,9 +997,9 @@ public void cancelTransference(OCFile file) { } // for both files and folders - FileDownloadWorker.FileDownloaderBinder downloaderBinder = fileActivity.getFileDownloaderBinder(); - if (downloaderBinder != null && downloaderBinder.isDownloading(currentUser, file)) { - downloaderBinder.cancelPendingOrCurrentDownloads(); + FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); + if (fileDownloadHelper.isDownloading(currentUser, file)) { + fileDownloadHelper.cancelPendingOrCurrentDownloads(currentUser, file); } FileUploaderBinder uploaderBinder = fileActivity.getFileUploaderBinder(); if (uploaderBinder != null && uploaderBinder.isUploading(currentUser, file)) { diff --git a/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java index d7c05e595409..4aa7a19ba7c5 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java @@ -261,8 +261,8 @@ private void setButtonsForRemote() { public void listenForTransferProgress() { - if (mProgressListener != null && !mListening && containerActivity.getFileDownloaderBinder() != null) { - containerActivity.getFileDownloaderBinder().addDataTransferProgressListener(mProgressListener, getFile()); + if (mProgressListener != null && !mListening && containerActivity.getFileDownloadProgressListener() != null) { + containerActivity.getFileDownloadProgressListener().addDataTransferProgressListener(mProgressListener, getFile()); mListening = true; setButtonsForTransferring(); } @@ -270,8 +270,8 @@ public void listenForTransferProgress() { public void leaveTransferProgress() { - if (mProgressListener != null && containerActivity.getFileDownloaderBinder() != null) { - containerActivity.getFileDownloaderBinder() + if (mProgressListener != null && containerActivity.getFileDownloadProgressListener() != null) { + containerActivity.getFileDownloadProgressListener() .removeDataTransferProgressListener(mProgressListener, getFile()); mListening = false; } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index aacea713eb58..34a26831e63e 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -37,10 +37,11 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; -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.WorkerState; +import com.nextcloud.model.WorkerStateLiveData; import com.nextcloud.utils.extensions.IntentExtensionsKt; import com.owncloud.android.MainApp; import com.owncloud.android.R; @@ -99,6 +100,8 @@ public class PreviewImageActivity extends FileActivity implements private DownloadFinishReceiver mDownloadFinishReceiver; private UploadFinishReceiver mUploadFinishReceiver; private View mFullScreenAnchorView; + private boolean isDownloadWorkStarted = false; + @Inject AppPreferences preferences; @Inject LocalBroadcastManager localBroadcastManager; @@ -146,6 +149,8 @@ protected void onCreate(Bundle savedInstanceState) { } else { mRequestWaitingForBinder = false; } + + observeWorkerState(); } public void toggleActionBarVisibility(boolean hide) { @@ -299,6 +304,25 @@ private void onSynchronizeFileOperationFinish(RemoteOperationResult result) { } } + private void observeWorkerState() { + WorkerStateLiveData.Companion.getInstance().observe(this, state -> { + if (state instanceof WorkerState.Download) { + Log_OC.d(TAG, "Download worker started"); + isDownloadWorkStarted = true; + + if (mRequestWaitingForBinder) { + mRequestWaitingForBinder = false; + Log_OC.d(TAG, "Simulating reselection of current page after connection " + + "of download binder"); + onPageSelected(mViewPager.getCurrentItem()); + } + } else { + Log_OC.d(TAG, "Download worker stopped"); + isDownloadWorkStarted = false; + } + }); + } + @Override protected ServiceConnection newTransferenceServiceConnection() { return new PreviewImageServiceConnection(); @@ -309,18 +333,7 @@ private class PreviewImageServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName component, IBinder service) { - if (component.equals(new ComponentName(PreviewImageActivity.this, - FileDownloadWorker.class))) { - mDownloaderBinder = (FileDownloadWorker.FileDownloaderBinder) service; - if (mRequestWaitingForBinder) { - mRequestWaitingForBinder = false; - Log_OC.d(TAG, "Simulating reselection of current page after connection " + - "of download binder"); - onPageSelected(mViewPager.getCurrentItem()); - } - - } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service connected"); mUploaderBinder = (FileUploaderBinder) service; @@ -331,10 +344,6 @@ public void onServiceConnected(ComponentName component, IBinder service) { @Override public void onServiceDisconnected(ComponentName component) { if (component.equals(new ComponentName(PreviewImageActivity.this, - FileDownloadWorker.class))) { - Log_OC.d(TAG, "Download service suddenly disconnected"); - mDownloaderBinder = null; - } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) { Log_OC.d(TAG, "Upload service suddenly disconnected"); mUploaderBinder = null; @@ -425,7 +434,7 @@ public void requestForDownload(OCFile file, String downloadBehaviour) { public void onPageSelected(int position) { mSavedPosition = position; mHasSavedPosition = true; - if (mDownloaderBinder == null) { + if (!isDownloadWorkStarted) { mRequestWaitingForBinder = true; } else { OCFile currentFile = mPreviewImagePagerAdapter.getFileAt(position); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt index 8de694773eed..8e6d15c2f9ef 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt @@ -27,9 +27,7 @@ package com.owncloud.android.ui.preview import android.app.Activity -import android.content.ComponentName import android.content.Intent -import android.content.ServiceConnection import android.content.res.Configuration import android.graphics.Bitmap import android.graphics.BitmapFactory @@ -39,7 +37,6 @@ import android.net.Uri import android.os.AsyncTask import android.os.Bundle import android.os.Handler -import android.os.IBinder import android.os.Looper import android.view.Menu import android.view.MenuItem @@ -65,8 +62,6 @@ import androidx.media3.ui.PlayerView import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.di.Injectable -import com.nextcloud.client.files.downloader.FileDownloadHelper -import com.nextcloud.client.files.downloader.FileDownloadWorker import com.nextcloud.client.jobs.BackgroundJobManager import com.nextcloud.client.media.ExoplayerListener import com.nextcloud.client.media.NextcloudExoPlayer.createNextcloudExoplayer @@ -563,33 +558,12 @@ class PreviewMediaActivity : } } - override fun newTransferenceServiceConnection(): ServiceConnection { - return PreviewMediaServiceConnection() - } - private fun onSynchronizeFileOperationFinish(result: RemoteOperationResult<*>?) { result?.let { invalidateOptionsMenu() } } - private inner class PreviewMediaServiceConnection : ServiceConnection { - override fun onServiceConnected(componentName: ComponentName?, service: IBinder?) { - componentName?.let { - if (it == ComponentName(this@PreviewMediaActivity, FileDownloadWorker::class.java)) { - mDownloaderBinder = service as FileDownloadWorker.FileDownloaderBinder - } - } - } - - override fun onServiceDisconnected(componentName: ComponentName?) { - if (componentName == ComponentName(this@PreviewMediaActivity, FileDownloadWorker::class.java)) { - Log_OC.d(PreviewImageActivity.TAG, "Download service suddenly disconnected") - mDownloaderBinder = null - } - } - } - override fun downloadFile(file: OCFile?, packageName: String?, activityName: String?) { requestForDownload(file, OCFileListFragment.DOWNLOAD_SEND, packageName, activityName) } From a6c88a421134c4db99f75fa06149771d4710dec7 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 14:15:43 +0100 Subject: [PATCH 132/189] Fix code analytics Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 124 ++++-------------- .../files/downloader/FileDownloadWorker.kt | 5 +- .../nextcloud/client/jobs/FilesExportWork.kt | 4 +- .../android/files/FileMenuFilter.java | 7 +- .../operations/SynchronizeFileOperation.java | 13 +- .../SynchronizeFolderOperation.java | 4 +- .../ui/activity/ConflictsResolveActivity.kt | 4 +- .../android/ui/activity/FileActivity.java | 3 +- .../ui/activity/FileDisplayActivity.java | 9 +- .../ui/activity/ManageAccountsActivity.java | 5 +- .../android/ui/adapter/OCFileListDelegate.kt | 26 ++-- .../ui/fragment/FileDetailFragment.java | 6 +- .../ui/helpers/FileOperationsHelper.java | 7 +- .../ui/preview/PreviewImageActivity.java | 6 +- .../ui/preview/PreviewMediaActivity.kt | 7 +- .../ui/preview/PreviewMediaFragment.java | 5 +- 16 files changed, 71 insertions(+), 164 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index e4d7ce201ebe..189b6263dba0 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -27,14 +27,13 @@ import com.owncloud.android.MainApp import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager -import com.owncloud.android.lib.common.network.OnDatatransferProgressListener import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType import com.owncloud.android.utils.MimeTypeUtil import java.io.File import javax.inject.Inject -class FileDownloadHelper : OnDatatransferProgressListener { +class FileDownloadHelper { @Inject lateinit var backgroundJobManager: BackgroundJobManager @@ -42,49 +41,20 @@ class FileDownloadHelper : OnDatatransferProgressListener { @Inject lateinit var uploadsStorageManager: UploadsStorageManager - private val boundListeners: MutableMap = HashMap() - private var currentDownload: DownloadFileOperation? = null + companion object { + private var instance: FileDownloadHelper? = null - init { - MainApp.getAppComponent().inject(this) - } - - fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { - if (file == null || listener == null) { - return - } - - boundListeners[file.fileId] = listener - } - - fun removeDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { - if (file == null || listener == null) { - return - } - - val fileId = file.fileId - if (boundListeners[fileId] === listener) { - boundListeners.remove(fileId) + fun instance(): FileDownloadHelper { + return if (instance == null) { + FileDownloadHelper() + } else { + instance!! + } } } - override fun onTransferProgress( - progressRate: Long, - totalTransferredSoFar: Long, - totalToTransfer: Long, - fileName: String - ) { - val listener = boundListeners[currentDownload?.file?.fileId] - listener?.onTransferProgress( - progressRate, - totalTransferredSoFar, - totalToTransfer, - fileName - ) - } - - fun setCurrentDownload(operation: DownloadFileOperation) { - currentDownload = operation + init { + MainApp.getAppComponent().inject(this) } fun isDownloading(user: User?, file: OCFile?): Boolean { @@ -145,75 +115,25 @@ class FileDownloadHelper : OnDatatransferProgressListener { storageManager?.saveConflict(file, null) } - fun downloadFile(user: User, ocFile: OCFile) { - backgroundJobManager.startFileDownloadJob( - user, - ocFile, - "", - DownloadType.DOWNLOAD, - "", - "", - null - ) - } - - fun downloadFile(user: User, ocFile: OCFile, behaviour: String) { - backgroundJobManager.startFileDownloadJob( - user, - ocFile, - behaviour, - DownloadType.DOWNLOAD, - "", - "", - null - ) - } - - fun downloadFile(user: User, ocFile: OCFile, behaviour: String, packageName: String, activityName: String) { - backgroundJobManager.startFileDownloadJob( - user, - ocFile, - behaviour, - DownloadType.DOWNLOAD, - packageName, - packageName, - null - ) - } - - fun downloadFile(user: User, ocFile: OCFile, downloadType: DownloadType) { - backgroundJobManager.startFileDownloadJob( - user, - ocFile, - "", - downloadType, - "", - "", - null - ) + fun downloadFileIfNotStartedBefore(user: User, file: OCFile) { + if (!isDownloading(user, file)) { + downloadFile(user, file, downloadType = DownloadType.DOWNLOAD) + } } - fun downloadFile(user: User, ocFile: OCFile, conflictUploadId: Long) { - backgroundJobManager.startFileDownloadJob( - user, - ocFile, - "", - DownloadType.DOWNLOAD, - "", - "", - conflictUploadId - ) + fun downloadFile(user: User, ocFile: OCFile) { + downloadFile(user, ocFile, downloadType = DownloadType.DOWNLOAD) } @Suppress("LongParameterList") fun downloadFile( user: User, ocFile: OCFile, - behaviour: String, - downloadType: DownloadType?, - activityName: String, - packageName: String, - conflictUploadId: Long? + behaviour: String = "", + downloadType: DownloadType? = DownloadType.DOWNLOAD, + activityName: String = "", + packageName: String = "", + conflictUploadId: Long? = null ) { backgroundJobManager.startFileDownloadJob( user, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index c432f253e052..0dde3df25d41 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -97,7 +97,6 @@ class FileDownloadWorker( private val pendingDownloads = IndexedForest() private var downloadProgressListener = FileDownloadProgressListener() private var currentUser = Optional.empty() - private val helper = FileDownloadHelper() private var startedDownload = false private var storageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null @@ -230,7 +229,7 @@ class FileDownloadWorker( downloadResult = currentDownload?.execute(downloadClient) if (downloadResult?.isSuccess == true && currentDownload?.downloadType === DownloadType.DOWNLOAD) { getCurrentFile()?.let { - helper.saveFile(it, currentDownload, storageManager) + FileDownloadHelper.instance().saveFile(it, currentDownload, storageManager) } } } catch (e: Exception) { @@ -366,7 +365,7 @@ class FileDownloadWorker( private val boundListeners: MutableMap = HashMap() fun isDownloading(user: User?, file: OCFile?): Boolean { - return helper.isDownloading(user, file) + return FileDownloadHelper.instance().isDownloading(user, file) } fun addDataTransferProgressListener(listener: OnDatatransferProgressListener?, file: OCFile?) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt index c5f82cc89df2..05586ba96569 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt @@ -111,10 +111,10 @@ class FilesExportWork( } private fun downloadFile(ocFile: OCFile) { - FileDownloadHelper().downloadFile( + FileDownloadHelper.instance().downloadFile( user, ocFile, - DownloadType.EXPORT + downloadType = DownloadType.EXPORT ) } diff --git a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java index 6639a201c320..e209d21bc301 100644 --- a/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/app/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -380,9 +380,8 @@ private boolean anyFileSynchronizing() { if (componentsGetter != null && !files.isEmpty() && user != null) { OperationsServiceBinder opsBinder = componentsGetter.getOperationsServiceBinder(); FileUploaderBinder uploaderBinder = componentsGetter.getFileUploaderBinder(); - FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); synchronizing = anyFileSynchronizing(opsBinder) || // comparing local and remote - anyFileDownloading(fileDownloadHelper) || + anyFileDownloading() || anyFileUploading(uploaderBinder); } return synchronizing; @@ -398,9 +397,9 @@ private boolean anyFileSynchronizing(OperationsServiceBinder opsBinder) { return synchronizing; } - private boolean anyFileDownloading(FileDownloadHelper downloadHelper) { + private boolean anyFileDownloading() { for (OCFile file : files) { - if (downloadHelper.isDownloading(user, file)) { + if (FileDownloadHelper.Companion.instance().isDownloading(user, file)) { return true; } } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java index 48b7aa9b701f..e993df4f66f4 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -309,30 +309,19 @@ private void requestForUpload(OCFile file) { mTransferWasRequested = true; } - - /** - * Requests for a download to the FileDownloader service - * - * @param file OCFile object representing the file to download - */ private void requestForDownload(OCFile file) { - FileDownloadHelper downloadHelper = new FileDownloadHelper(); - - downloadHelper.downloadFile( + FileDownloadHelper.Companion.instance().downloadFile( mUser, file); mTransferWasRequested = true; } - public boolean transferWasRequested() { return mTransferWasRequested; } - public OCFile getLocalFile() { return mLocalFile; } - } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index 0cb9cff609e8..d6228d3d67bd 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -445,14 +445,12 @@ private void syncContents() throws OperationCancelledException { } private void startDirectDownloads() throws OperationCancelledException { - FileDownloadHelper downloadHelper = new FileDownloadHelper(); - for (OCFile file : mFilesForDirectDownload) { synchronized(mCancellationRequested) { if (mCancellationRequested.get()) { throw new OperationCancelledException(); } - downloadHelper.downloadFile(user, file); + FileDownloadHelper.Companion.instance().downloadFile(user, file); } } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt index 0a1f8d3bffbe..b85f3925c5e1 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt @@ -115,10 +115,10 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener Decision.KEEP_SERVER -> if (!shouldDeleteLocal()) { // Overwrite local file file?.let { - FileDownloadHelper().downloadFile( + FileDownloadHelper.instance().downloadFile( getUser().orElseThrow { RuntimeException() }, file, - conflictUploadId + conflictUploadId = conflictUploadId ) } } else { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index fb0c623fabdc..fca1cbd96bc1 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -166,7 +166,6 @@ public abstract class FileActivity extends DrawerActivity private boolean mResumed; - protected FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); protected FileDownloadWorker.FileDownloadProgressListener fileDownloadProgressListener; protected FileUploaderBinder mUploaderBinder; private ServiceConnection mUploadServiceConnection; @@ -235,7 +234,7 @@ protected void onCreate(Bundle savedInstanceState) { Context.BIND_AUTO_CREATE); if (user != null) { - new FileDownloadHelper().downloadFile(user, mFile); + FileDownloadHelper.Companion.instance().downloadFile(user, mFile); } mUploadServiceConnection = newTransferenceServiceConnection(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index a0e94413e315..543d2a982dbe 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -65,6 +65,7 @@ import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; import com.nextcloud.client.files.DeepLinkHandler; +import com.nextcloud.client.files.downloader.FileDownloadHelper; import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.media.PlayerServiceConnection; import com.nextcloud.client.network.ClientFactory; @@ -1896,9 +1897,7 @@ public void onTransferStateChanged(OCFile file, boolean downloading, boolean upl private void requestForDownload() { User user = getUser().orElseThrow(RuntimeException::new); - if (!fileDownloadHelper.isDownloading(user, mWaitingToPreview)) { - fileDownloadHelper.downloadFile(user, mWaitingToPreview); - } + FileDownloadHelper.Companion.instance().downloadFileIfNotStartedBefore(user, mWaitingToPreview); } @Override @@ -1968,8 +1967,8 @@ public void run() { private void requestForDownload(OCFile file, String downloadBehaviour, String packageName, String activityName) { final User currentUser = getUser().orElseThrow(RuntimeException::new); - if (!fileDownloadHelper.isDownloading(currentUser, file)) { - fileDownloadHelper.downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); + if (!FileDownloadHelper.Companion.instance().isDownloading(currentUser, file)) { + FileDownloadHelper.Companion.instance().downloadFile(currentUser, file, downloadBehaviour, DownloadType.DOWNLOAD, activityName, packageName, null); } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index a26c4f95c13e..29f102988a2a 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -41,6 +41,7 @@ import com.google.common.collect.Sets; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; +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; @@ -341,7 +342,7 @@ public void run(AccountManagerFuture future) { mUploaderBinder.cancel(accountName); } - fileDownloadHelper.cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); + FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); } User currentUser = getUserAccountManager().getUser(); @@ -431,7 +432,7 @@ private void performAccountRemoval(User user) { mUploaderBinder.cancel(user); } - fileDownloadHelper.cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); + FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); backgroundJobManager.startAccountRemovalJob(user.getAccountName(), false); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 5cd63ffe60c8..9b430135b56f 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -341,27 +341,31 @@ class OCFileListDelegate( private fun showLocalFileIndicator(file: OCFile, gridViewHolder: ListGridImageViewHolder) { val operationsServiceBinder = transferServiceGetter.operationsServiceBinder - val fileDownloadHelper = FileDownloadHelper() val fileUploaderBinder = transferServiceGetter.fileUploaderBinder - when { + + val icon: Int? = when { operationsServiceBinder?.isSynchronizing(user, file) == true || - fileDownloadHelper.isDownloading(user, file) || + FileDownloadHelper.instance().isDownloading(user, file) || fileUploaderBinder?.isUploading(user, file) == true -> { // synchronizing, downloading or uploading - gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing) - gridViewHolder.localFileIndicator.visibility = View.VISIBLE + R.drawable.ic_synchronizing } file.etagInConflict != null -> { - // conflict - gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing_error) - gridViewHolder.localFileIndicator.visibility = View.VISIBLE + R.drawable.ic_synchronizing_error } file.isDown -> { - // downloaded - gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synced) - gridViewHolder.localFileIndicator.visibility = View.VISIBLE + R.drawable.ic_synced } + else -> { null } } + + gridViewHolder.localFileIndicator.run { + icon?.let { + setImageResource(icon) + visibility = View.VISIBLE + } + } + } private fun showShareIcon(gridViewHolder: ListGridImageViewHolder, file: OCFile) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 1801404df9f4..cecc01838c49 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -534,10 +534,9 @@ public void updateFileDetails(boolean transferring, boolean refresh) { setFavoriteIconStatus(file.isFavorite()); // configure UI for depending upon local state of the file - FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); if (transferring - || (fileDownloadHelper.isDownloading(user, file)) + || (FileDownloadHelper.Companion.instance().isDownloading(user, file)) || (uploaderBinder != null && uploaderBinder.isUploading(user, file))) { setButtonsForTransferring(); @@ -659,9 +658,8 @@ private void setButtonsForTransferring() { // show the progress bar for the transfer binding.progressBlock.setVisibility(View.VISIBLE); binding.progressText.setVisibility(View.VISIBLE); - FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); FileUploaderBinder uploaderBinder = containerActivity.getFileUploaderBinder(); - if (fileDownloadHelper.isDownloading(user, getFile())) { + if (FileDownloadHelper.Companion.instance().isDownloading(user, getFile())) { binding.progressText.setText(R.string.downloader_download_in_progress_ticker); } else { if (uploaderBinder != null && uploaderBinder.isUploading(user, getFile())) { diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index a072ddd7cd23..69ee619382b2 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -996,11 +996,10 @@ public void cancelTransference(OCFile file) { } } - // for both files and folders - FileDownloadHelper fileDownloadHelper = new FileDownloadHelper(); - if (fileDownloadHelper.isDownloading(currentUser, file)) { - fileDownloadHelper.cancelPendingOrCurrentDownloads(currentUser, file); + if (FileDownloadHelper.Companion.instance().isDownloading(currentUser, file)) { + FileDownloadHelper.Companion.instance().cancelPendingOrCurrentDownloads(currentUser, file); } + FileUploaderBinder uploaderBinder = fileActivity.getFileUploaderBinder(); if (uploaderBinder != null && uploaderBinder.isUploading(currentUser, file)) { uploaderBinder.cancel(currentUser.toPlatformAccount(), file); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 34a26831e63e..8915ed9c1b46 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -37,6 +37,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; +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; @@ -54,6 +55,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.operations.DownloadType; import com.owncloud.android.operations.RemoveFileOperation; import com.owncloud.android.operations.SynchronizeFileOperation; import com.owncloud.android.ui.activity.FileActivity; @@ -419,8 +421,8 @@ public void requestForDownload(OCFile file) { public void requestForDownload(OCFile file, String downloadBehaviour) { final User user = getUser().orElseThrow(RuntimeException::new); - if (!fileDownloadHelper.isDownloading(user, file)) { - fileDownloadHelper.downloadFile(user, file, downloadBehaviour); + if (!FileDownloadHelper.Companion.instance().isDownloading(user, file)) { + FileDownloadHelper.Companion.instance().downloadFile(user, file, downloadBehaviour, DownloadType.DOWNLOAD, "", "", null); } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt index 8e6d15c2f9ef..23d7bd00b40f 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt @@ -62,6 +62,7 @@ import androidx.media3.ui.PlayerView import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.di.Injectable +import com.nextcloud.client.files.downloader.FileDownloadHelper import com.nextcloud.client.jobs.BackgroundJobManager import com.nextcloud.client.media.ExoplayerListener import com.nextcloud.client.media.NextcloudExoPlayer.createNextcloudExoplayer @@ -82,6 +83,7 @@ import com.owncloud.android.lib.common.operations.OnRemoteOperationListener import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.operations.DownloadType import com.owncloud.android.operations.RemoveFileOperation import com.owncloud.android.operations.SynchronizeFileOperation import com.owncloud.android.ui.activity.FileActivity @@ -574,16 +576,17 @@ class PreviewMediaActivity : packageName: String? = null, activityName: String? = null ) { - if (fileDownloadHelper.isDownloading(user, file)) { + if (FileDownloadHelper.instance().isDownloading(user, file)) { return } user?.let { user -> file?.let { file -> - fileDownloadHelper.downloadFile( + FileDownloadHelper.instance().downloadFile( user, file, downloadBehavior ?: "", + DownloadType.DOWNLOAD, packageName ?: "", activityName ?: "" ) diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index 28c3e4d4f314..a1ef3e805734 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -131,7 +131,6 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene private boolean autoplay; private boolean isLivePhoto; - private final FileDownloadHelper downloadHelper = new FileDownloadHelper(); private boolean prepared; private PlayerServiceConnection mediaPlayerServiceConnection; @@ -479,9 +478,7 @@ public void onFileActionChosen(final int itemId) { getView(), backgroundJobManager); } else if (itemId == R.id.action_download_file) { - if (!downloadHelper.isDownloading(user, getFile())) { - downloadHelper.downloadFile(user, getFile()); - } + FileDownloadHelper.Companion.instance().downloadFileIfNotStartedBefore(user, getFile()); } } From c135e24c4b02b1dd9a5e87afc01f1e9f6946e381 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 14:19:25 +0100 Subject: [PATCH 133/189] Fix code analytics Signed-off-by: alperozturk --- .../com/nextcloud/client/files/downloader/FileDownloadHelper.kt | 2 -- .../java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt | 1 - 2 files changed, 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 189b6263dba0..9af4f2162e3a 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -77,8 +77,6 @@ class FileDownloadHelper { currentDownload.cancel() } - - // removePendingDownload(accountName) } fun saveFile( diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 9b430135b56f..e4fef4e2999b 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -365,7 +365,6 @@ class OCFileListDelegate( visibility = View.VISIBLE } } - } private fun showShareIcon(gridViewHolder: ListGridImageViewHolder, file: OCFile) { From 5c31d91149a73a33ea9fb94e68b83bbbca12ba27 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 14:26:32 +0100 Subject: [PATCH 134/189] Fix code analytics Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadHelper.kt | 6 ++---- .../client/files/downloader/FileDownloadWorker.kt | 4 ++-- .../java/com/nextcloud/model/WorkerStateLiveData.kt | 13 ++++++------- .../android/ui/activity/FileDisplayActivity.java | 2 +- .../android/ui/activity/ManageAccountsActivity.java | 2 +- .../android/ui/preview/PreviewImageActivity.java | 2 +- 6 files changed, 13 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 9af4f2162e3a..cc175c2ce7e6 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -45,10 +45,8 @@ class FileDownloadHelper { private var instance: FileDownloadHelper? = null fun instance(): FileDownloadHelper { - return if (instance == null) { - FileDownloadHelper() - } else { - instance!! + return instance ?: synchronized(this) { + instance ?: FileDownloadHelper().also { instance = it } } } } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 0dde3df25d41..8b826be235c1 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -179,11 +179,11 @@ class FileDownloadWorker( } private fun setWorkerState(user: User?, file: DownloadFileOperation?) { - WorkerStateLiveData.instance?.setWorkState(WorkerState.Download(user, file)) + WorkerStateLiveData.instance().setWorkState(WorkerState.Download(user, file)) } private fun setIdleWorkerState() { - WorkerStateLiveData.instance?.setWorkState(WorkerState.Idle) + WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } private fun addAccountUpdateListener() { diff --git a/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt b/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt index 8863b6dddac2..54fd35f4d702 100644 --- a/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt +++ b/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt @@ -30,13 +30,12 @@ class WorkerStateLiveData private constructor() : LiveData() { } companion object { - var instance: WorkerStateLiveData? = null - get() { - if (field == null) { - field = WorkerStateLiveData() - } - return field + private var instance: WorkerStateLiveData? = null + + fun instance(): WorkerStateLiveData { + return instance ?: synchronized(this) { + instance ?: WorkerStateLiveData().also { instance = it } } - private set + } } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 543d2a982dbe..d54374c1c4e0 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1563,7 +1563,7 @@ public boolean isDrawerIndicatorAvailable() { } private void observeWorkerState() { - WorkerStateLiveData.Companion.getInstance().observe(this, state -> { + WorkerStateLiveData.Companion.instance().observe(this, state -> { if (state instanceof WorkerState.Download) { Log_OC.d(TAG, "Download worker started"); handleDownloadWorkerState(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 29f102988a2a..955c240d0857 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -518,7 +518,7 @@ public void onOptionItemClicked(User user, View view) { } private void observeWorkerState() { - WorkerStateLiveData.Companion.getInstance().observe(this, state -> { + WorkerStateLiveData.Companion.instance().observe(this, state -> { if (state instanceof WorkerState.Download) { Log_OC.d(TAG, "Download worker started"); workerAccountName = ((WorkerState.Download) state).getUser().getAccountName(); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 8915ed9c1b46..80c07b03d7a7 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -307,7 +307,7 @@ private void onSynchronizeFileOperationFinish(RemoteOperationResult result) { } private void observeWorkerState() { - WorkerStateLiveData.Companion.getInstance().observe(this, state -> { + WorkerStateLiveData.Companion.instance().observe(this, state -> { if (state instanceof WorkerState.Download) { Log_OC.d(TAG, "Download worker started"); isDownloadWorkStarted = true; From bd1de66a14fcf39101d6212e9543639e439d955a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 29 Dec 2023 15:53:35 +0100 Subject: [PATCH 135/189] Fixes notification manager Signed-off-by: alperozturk --- .../download/DownloadNotificationManager.kt | 88 ++++++++++--------- .../utils/extensions/ContextExtensions.kt | 5 -- 2 files changed, 46 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt index 2c7d4e41b4e4..397e8a5191b9 100644 --- a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt @@ -48,14 +48,14 @@ class DownloadNotificationManager(private val context: Context, private val view private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager fun init() { - notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) - .setContentTitle(context.resources.getString(R.string.app_name)) - .setContentText(context.resources.getString(R.string.foreground_service_download)) - .setSmallIcon(R.drawable.notification_icon) - .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply { + setContentTitle(context.resources.getString(R.string.app_name)) + setContentText(context.resources.getString(R.string.worker_download)) + setSmallIcon(R.drawable.notification_icon) + setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + } } notification = notificationBuilder.build() @@ -63,44 +63,50 @@ class DownloadNotificationManager(private val context: Context, private val view @Suppress("MagicNumber") fun notifyForStart(operation: DownloadFileOperation) { - notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils) - .setSmallIcon(R.drawable.notification_icon) - .setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) - .setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) - .setOngoing(true) - .setProgress(100, 0, operation.size < 0) - .setContentText( + notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply { + setSmallIcon(R.drawable.notification_icon) + setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) + setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) + setOngoing(true) + setProgress(100, 0, operation.size < 0) + setContentText( String.format( context.getString(R.string.downloader_download_in_progress_content), 0, File(operation.savePath).name ) ) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) + } } } + fun prepareForResult( + downloadResult: RemoteOperationResult<*>, + needsToUpdateCredentials: Boolean + ) { + val tickerId = getTickerId(downloadResult.isSuccess, needsToUpdateCredentials) + + notificationBuilder + .setTicker(context.getString(tickerId)) + .setContentTitle(context.getString(tickerId)) + .setAutoCancel(true) + .setOngoing(false) + .setProgress(0, 0, false) + } + @Suppress("MagicNumber") fun notifyForResult(result: RemoteOperationResult<*>, download: DownloadFileOperation) { dismissDownloadInProgressNotification() val tickerId = getTickerId(result.isSuccess, null) val notifyId = SecureRandom().nextInt() - - val contentText = if (result.isSuccess) { - download.file.fileName - } else { - ErrorMessageAdapter.getErrorCauseMessage( - result, - download, - context.resources - ) - } + val resultText = getResultText(result, download) notificationBuilder.run { setTicker(context.getString(tickerId)) - setContentText(contentText) + setContentText(resultText) notificationManager.notify(notifyId, this.build()) } @@ -111,6 +117,18 @@ class DownloadNotificationManager(private val context: Context, private val view ) } + private fun getResultText(result: RemoteOperationResult<*>, download: DownloadFileOperation): String { + return if (result.isSuccess) { + download.file.fileName + } else { + ErrorMessageAdapter.getErrorCauseMessage( + result, + download, + context.resources + ) + } + } + private fun getTickerId(isSuccess: Boolean, needsToUpdateCredentials: Boolean?): Int { return if (needsToUpdateCredentials == true) { R.string.downloader_download_failed_credentials_error @@ -123,20 +141,6 @@ class DownloadNotificationManager(private val context: Context, private val view } } - fun prepareForResult( - downloadResult: RemoteOperationResult<*>, - needsToUpdateCredentials: Boolean - ) { - val tickerId = getTickerId(downloadResult.isSuccess, needsToUpdateCredentials) - - notificationBuilder - .setTicker(context.getString(tickerId)) - .setContentTitle(context.getString(tickerId)) - .setAutoCancel(true) - .setOngoing(false) - .setProgress(0, 0, false) - } - @Suppress("MagicNumber") fun updateDownloadProgressNotification(filePath: String, percent: Int, totalToTransfer: Long) { notificationBuilder.setProgress(100, percent, totalToTransfer < 0) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt index ee0b30e2ad0e..6dc7dde71e2f 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt @@ -27,7 +27,6 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.Build -import androidx.work.WorkManager import com.owncloud.android.datamodel.ReceiverFlag @SuppressLint("UnspecifiedRegisterReceiverFlag") @@ -38,7 +37,3 @@ fun Context.registerBroadcastReceiver(receiver: BroadcastReceiver?, filter: Inte registerReceiver(receiver, filter) } } - -fun Context.isWorkScheduled(tag: String): Boolean { - return WorkManager.getInstance(this).isWorkScheduled(tag) -} From 80b08e4fcd1ee2015d8602cf24360c136f6b0bd6 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 12:57:15 +0100 Subject: [PATCH 136/189] Rebase master Signed-off-by: alperozturk --- .../downloader/DownloadNotificationManager.kt | 148 ++++++++------ .../files/downloader/FileDownloadWorker.kt | 1 - .../download/DownloadNotificationManager.kt | 189 ------------------ 3 files changed, 85 insertions(+), 253 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 1683ceade7fb..1457e603fb8e 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -28,34 +28,31 @@ import android.content.Context import android.content.Intent import android.graphics.BitmapFactory import android.os.Build -import android.os.Handler -import android.os.Looper import androidx.core.app.NotificationCompat +import com.nextcloud.client.account.User import com.owncloud.android.R +import com.owncloud.android.authentication.AuthenticatorActivity +import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.resources.files.FileUtils import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.ui.notifications.NotificationUtils +import com.owncloud.android.utils.ErrorMessageAdapter import com.owncloud.android.utils.theme.ViewThemeUtils import java.io.File import java.security.SecureRandom -@Suppress("TooManyFunctions") -class DownloadNotificationManager( - private val id: Int, - private val context: Context, - private val viewThemeUtils: ViewThemeUtils -) { +class DownloadNotificationManager(private val context: Context, private val viewThemeUtils: ViewThemeUtils) { - private var notification: Notification - private var notificationBuilder: NotificationCompat.Builder + private var notification: Notification? = null + private lateinit var notificationBuilder: NotificationCompat.Builder private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - init { + fun init() { notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply { setContentTitle(context.resources.getString(R.string.app_name)) + setContentText(context.resources.getString(R.string.worker_download)) setSmallIcon(R.drawable.notification_icon) setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) } @@ -65,14 +62,16 @@ class DownloadNotificationManager( } @Suppress("MagicNumber") - fun prepareForStart(operation: DownloadFileOperation) { + fun notifyForStart(operation: DownloadFileOperation) { notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply { setSmallIcon(R.drawable.notification_icon) + setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) + setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) setOngoing(true) setProgress(100, 0, operation.size < 0) setContentText( String.format( - context.getString(R.string.downloader_download_in_progress), 0, + context.getString(R.string.downloader_download_in_progress_content), 0, File(operation.savePath).name ) ) @@ -80,70 +79,101 @@ class DownloadNotificationManager( if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) } - - notificationManager.notify( - id, - this.build() - ) } } - fun prepareForResult() { + fun prepareForResult( + downloadResult: RemoteOperationResult<*>, + needsToUpdateCredentials: Boolean + ) { + val tickerId = getTickerId(downloadResult.isSuccess, needsToUpdateCredentials) + notificationBuilder + .setTicker(context.getString(tickerId)) + .setContentTitle(context.getString(tickerId)) .setAutoCancel(true) .setOngoing(false) .setProgress(0, 0, false) } @Suppress("MagicNumber") - fun updateDownloadProgress(filePath: String, percent: Int, totalToTransfer: Long) { + fun notifyForResult(result: RemoteOperationResult<*>, download: DownloadFileOperation) { + dismissDownloadInProgressNotification() + + val tickerId = getTickerId(result.isSuccess, null) + val notifyId = SecureRandom().nextInt() + val resultText = getResultText(result, download) + notificationBuilder.run { - setProgress(100, percent, totalToTransfer < 0) - val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) - val text = - String.format(context.getString(R.string.downloader_download_in_progress), percent, fileName) - val title = - context.getString(R.string.downloader_download_in_progress_ticker) - updateNotificationText(title, text, false) + setTicker(context.getString(tickerId)) + setContentText(resultText) + notificationManager.notify(notifyId, this.build()) } + + NotificationUtils.cancelWithDelay( + notificationManager, + notifyId, + 2000 + ) } - @Suppress("MagicNumber") - fun showCompleteNotification(text: String) { - Handler(Looper.getMainLooper()).postDelayed({ - updateNotificationText(null, text, true) - dismissNotification() - }, 3000) + private fun getResultText(result: RemoteOperationResult<*>, download: DownloadFileOperation): String { + return if (result.isSuccess) { + download.file.fileName + } else { + ErrorMessageAdapter.getErrorCauseMessage( + result, + download, + context.resources + ) + } + } + + private fun getTickerId(isSuccess: Boolean, needsToUpdateCredentials: Boolean?): Int { + return if (needsToUpdateCredentials == true) { + R.string.downloader_download_failed_credentials_error + } else { + if (isSuccess) { + R.string.downloader_download_succeeded_ticker + } else { + R.string.downloader_download_failed_ticker + } + } } @Suppress("MagicNumber") - fun dismissNotification() { - Handler(Looper.getMainLooper()).postDelayed({ - notificationManager.cancel(id) - }, 2000) + fun updateDownloadProgressNotification(filePath: String, percent: Int, totalToTransfer: Long) { + notificationBuilder.setProgress(100, percent, totalToTransfer < 0) + val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) + val text = + String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) + notificationBuilder.setContentText(text) } - fun showNewNotification(text: String) { - val notifyId = SecureRandom().nextInt() + fun showDownloadInProgressNotification() { + notificationManager.notify( + R.string.downloader_download_in_progress_ticker, + notificationBuilder.build() + ) + } - notificationBuilder.run { - setProgress(0, 0, false) - setContentTitle(null) - setContentText(text) - setOngoing(false) - notificationManager.notify(notifyId, this.build()) - } + fun dismissDownloadInProgressNotification() { + notificationManager.cancel(R.string.downloader_download_in_progress_ticker) } - private fun updateNotificationText(title: String?, text: String, cancelProgressBar: Boolean) { - notificationBuilder.run { - if (cancelProgressBar) { - setProgress(0, 0, false) - } - setContentTitle(title) - setContentText(text) - notificationManager.notify(id, this.build()) + fun setCredentialContentIntent(user: User) { + val intent = Intent(context, AuthenticatorActivity::class.java).apply { + putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) + putExtra( + AuthenticatorActivity.EXTRA_ACTION, + AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN + ) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + addFlags(Intent.FLAG_FROM_BACKGROUND) } + + setContentIntent(intent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE) } fun setContentIntent(intent: Intent, flag: Int) { @@ -156,12 +186,4 @@ class DownloadNotificationManager( ) ) } - - fun getId(): Int { - return id - } - - fun getNotification(): Notification { - return notificationBuilder.build() - } } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 8b826be235c1..6c82b36a5b99 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -32,7 +32,6 @@ import androidx.work.WorkerParameters import com.google.gson.Gson import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager -import com.nextcloud.client.notifications.download.DownloadNotificationManager import com.nextcloud.java.util.Optional import com.nextcloud.model.WorkerState import com.nextcloud.model.WorkerStateLiveData diff --git a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt deleted file mode 100644 index 397e8a5191b9..000000000000 --- a/app/src/main/java/com/nextcloud/client/notifications/download/DownloadNotificationManager.kt +++ /dev/null @@ -1,189 +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 . - */ - -package com.nextcloud.client.notifications.download - -import android.app.Notification -import android.app.NotificationManager -import android.app.PendingIntent -import android.content.Context -import android.content.Intent -import android.graphics.BitmapFactory -import android.os.Build -import androidx.core.app.NotificationCompat -import com.nextcloud.client.account.User -import com.owncloud.android.R -import com.owncloud.android.authentication.AuthenticatorActivity -import com.owncloud.android.lib.common.operations.RemoteOperationResult -import com.owncloud.android.lib.resources.files.FileUtils -import com.owncloud.android.operations.DownloadFileOperation -import com.owncloud.android.ui.notifications.NotificationUtils -import com.owncloud.android.utils.ErrorMessageAdapter -import com.owncloud.android.utils.theme.ViewThemeUtils -import java.io.File -import java.security.SecureRandom - -class DownloadNotificationManager(private val context: Context, private val viewThemeUtils: ViewThemeUtils) { - - private var notification: Notification? = null - private lateinit var notificationBuilder: NotificationCompat.Builder - private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - - fun init() { - notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply { - setContentTitle(context.resources.getString(R.string.app_name)) - setContentText(context.resources.getString(R.string.worker_download)) - setSmallIcon(R.drawable.notification_icon) - setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) - } - } - - notification = notificationBuilder.build() - } - - @Suppress("MagicNumber") - fun notifyForStart(operation: DownloadFileOperation) { - notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply { - setSmallIcon(R.drawable.notification_icon) - setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) - setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) - setOngoing(true) - setProgress(100, 0, operation.size < 0) - setContentText( - String.format( - context.getString(R.string.downloader_download_in_progress_content), 0, - File(operation.savePath).name - ) - ) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) - } - } - } - - fun prepareForResult( - downloadResult: RemoteOperationResult<*>, - needsToUpdateCredentials: Boolean - ) { - val tickerId = getTickerId(downloadResult.isSuccess, needsToUpdateCredentials) - - notificationBuilder - .setTicker(context.getString(tickerId)) - .setContentTitle(context.getString(tickerId)) - .setAutoCancel(true) - .setOngoing(false) - .setProgress(0, 0, false) - } - - @Suppress("MagicNumber") - fun notifyForResult(result: RemoteOperationResult<*>, download: DownloadFileOperation) { - dismissDownloadInProgressNotification() - - val tickerId = getTickerId(result.isSuccess, null) - val notifyId = SecureRandom().nextInt() - val resultText = getResultText(result, download) - - notificationBuilder.run { - setTicker(context.getString(tickerId)) - setContentText(resultText) - notificationManager.notify(notifyId, this.build()) - } - - NotificationUtils.cancelWithDelay( - notificationManager, - notifyId, - 2000 - ) - } - - private fun getResultText(result: RemoteOperationResult<*>, download: DownloadFileOperation): String { - return if (result.isSuccess) { - download.file.fileName - } else { - ErrorMessageAdapter.getErrorCauseMessage( - result, - download, - context.resources - ) - } - } - - private fun getTickerId(isSuccess: Boolean, needsToUpdateCredentials: Boolean?): Int { - return if (needsToUpdateCredentials == true) { - R.string.downloader_download_failed_credentials_error - } else { - if (isSuccess) { - R.string.downloader_download_succeeded_ticker - } else { - R.string.downloader_download_failed_ticker - } - } - } - - @Suppress("MagicNumber") - fun updateDownloadProgressNotification(filePath: String, percent: Int, totalToTransfer: Long) { - notificationBuilder.setProgress(100, percent, totalToTransfer < 0) - val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) - val text = - String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) - notificationBuilder.setContentText(text) - } - - fun showDownloadInProgressNotification() { - notificationManager.notify( - R.string.downloader_download_in_progress_ticker, - notificationBuilder.build() - ) - } - - fun dismissDownloadInProgressNotification() { - notificationManager.cancel(R.string.downloader_download_in_progress_ticker) - } - - fun setCredentialContentIntent(user: User) { - val intent = Intent(context, AuthenticatorActivity::class.java).apply { - putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) - putExtra( - AuthenticatorActivity.EXTRA_ACTION, - AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN - ) - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) - addFlags(Intent.FLAG_FROM_BACKGROUND) - } - - setContentIntent(intent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE) - } - - fun setContentIntent(intent: Intent, flag: Int) { - notificationBuilder.setContentIntent( - PendingIntent.getActivity( - context, - System.currentTimeMillis().toInt(), - intent, - flag - ) - ) - } -} From a4e6c02d1232a9f060be97380f9603c30bb4cc07 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 3 Jan 2024 10:00:36 +0100 Subject: [PATCH 137/189] Simplify worker Signed-off-by: alperozturk --- .../files/downloader/FileDownloadWorker.kt | 28 ++++++------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 6c82b36a5b99..7a19cc5b885f 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -96,7 +96,6 @@ class FileDownloadWorker( private val pendingDownloads = IndexedForest() private var downloadProgressListener = FileDownloadProgressListener() private var currentUser = Optional.empty() - private var startedDownload = false private var storageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null private var user: User? = null @@ -109,7 +108,12 @@ class FileDownloadWorker( notificationManager.init() addAccountUpdateListener() - startDownloadForEachRequest(requestDownloads) + + requestDownloads.forEach { + downloadFile(it) + } + + setIdleWorkerState() Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() @@ -119,11 +123,6 @@ class FileDownloadWorker( } } - override fun onStopped() { - super.onStopped() - setIdleWorkerState() - } - private fun getRequestDownloads(): AbstractList { conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) @@ -190,26 +189,15 @@ class FileDownloadWorker( am.addOnAccountsUpdatedListener(this, null, false) } - private fun startDownloadForEachRequest(requestDownloads: AbstractList) { - val it: Iterator = requestDownloads.iterator() - - while (it.hasNext()) { - val next = it.next() - Log_OC.e(TAG, "Download Key: $next") - downloadFile(next) - } - - startedDownload = false - } - @Suppress("TooGenericExceptionCaught") private fun downloadFile(downloadKey: String) { - startedDownload = true currentDownload = pendingDownloads.get(downloadKey) if (currentDownload == null) { return } + + Log_OC.e(TAG, "FilesDownloadWorker downloading: $downloadKey") setWorkerState(user, currentDownload) val isAccountExist = accountManager.exists(currentDownload?.user?.toPlatformAccount()) From 1e28130b5db31e42ebd933ab08b34008e65ec33a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 3 Jan 2024 11:09:15 +0100 Subject: [PATCH 138/189] Add folder download job Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 24 +++- .../files/downloader/FileDownloadWorker.kt | 109 ++++++++++++------ .../client/jobs/BackgroundJobManager.kt | 9 +- .../client/jobs/BackgroundJobManagerImpl.kt | 64 +++++----- .../SynchronizeFolderOperation.java | 18 ++- 5 files changed, 145 insertions(+), 79 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index cc175c2ce7e6..24edd309a2d8 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -29,8 +29,10 @@ import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType +import com.owncloud.android.operations.SynchronizeFolderOperation import com.owncloud.android.utils.MimeTypeUtil import java.io.File +import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject class FileDownloadHelper { @@ -56,12 +58,24 @@ class FileDownloadHelper { } fun isDownloading(user: User?, file: OCFile?): Boolean { - return user != null && file != null && backgroundJobManager.isStartFileDownloadJobScheduled( + if (user == null || file == null) { + return false + } + + return backgroundJobManager.isStartFileDownloadJobScheduled( user, file ) } + private fun isFolderDownloading(folder: OCFile): Boolean { + for ((id, status) in SynchronizeFolderOperation.folderDownloadStatusPair) { + return id == folder.fileId && status + } + + return false + } + fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return backgroundJobManager.cancelFilesDownloadJob(user, file) @@ -117,8 +131,12 @@ class FileDownloadHelper { } } - fun downloadFile(user: User, ocFile: OCFile) { - downloadFile(user, ocFile, downloadType = DownloadType.DOWNLOAD) + fun downloadFolder(folder: OCFile, user: User, files: List) { + backgroundJobManager.startFolderDownloadJob(folder, user, files) + } + + fun downloadFile(user: User, file: OCFile) { + downloadFile(user, file, downloadType = DownloadType.DOWNLOAD) } @Suppress("LongParameterList") diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 7a19cc5b885f..577555680f97 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -26,10 +26,13 @@ import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener import android.app.PendingIntent import android.content.Context +import androidx.core.util.component1 +import androidx.core.util.component2 import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional @@ -43,6 +46,7 @@ import com.owncloud.android.lib.common.OwnCloudAccount import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.OwnCloudClientManagerFactory import com.owncloud.android.lib.common.network.OnDatatransferProgressListener +import com.owncloud.android.lib.common.operations.OperationCancelledException import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode import com.owncloud.android.lib.common.utils.Log_OC @@ -51,6 +55,7 @@ import com.owncloud.android.operations.DownloadType import com.owncloud.android.utils.theme.ViewThemeUtils import java.util.AbstractList import java.util.Vector +import java.util.concurrent.atomic.AtomicBoolean @Suppress("LongParameterList") class FileDownloadWorker( @@ -67,6 +72,7 @@ class FileDownloadWorker( const val USER_NAME = "USER" const val FILE = "FILE" + const val FILES = "FILES" const val BEHAVIOUR = "BEHAVIOUR" const val DOWNLOAD_TYPE = "DOWNLOAD_TYPE" const val ACTIVITY_NAME = "ACTIVITY_NAME" @@ -123,50 +129,47 @@ class FileDownloadWorker( } } + override fun onStopped() { + setIdleWorkerState() + super.onStopped() + } + private fun getRequestDownloads(): AbstractList { + val files = getFiles() + val downloadType = getDownloadType() + setUser() + conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? - val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) - val accountName = inputData.keyValueMap[USER_NAME] as String - user = accountManager.getUser(accountName).get() - val downloadTypeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? - val downloadType = if (downloadTypeAsString != null) { - if (downloadTypeAsString == DownloadType.DOWNLOAD.toString()) { - DownloadType.DOWNLOAD - } else { - DownloadType.EXPORT - } - } else { - null - } - val behaviour = inputData.keyValueMap[BEHAVIOUR] as String - val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String - val packageName = inputData.keyValueMap[PACKAGE_NAME] as String + val behaviour = inputData.keyValueMap[BEHAVIOUR] as String? ?: "" + val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String? ?: "" + val packageName = inputData.keyValueMap[PACKAGE_NAME] as String? ?: "" val requestedDownloads: AbstractList = Vector() return try { - val operation = DownloadFileOperation( - user, - file, - behaviour, - activityName, - packageName, - context, - downloadType - ) - - operation.addDownloadDataTransferProgressListener(this) - operation.addDownloadDataTransferProgressListener(downloadProgressListener) - val putResult = pendingDownloads.putIfAbsent( - user?.accountName, - file.remotePath, - operation - ) - - if (putResult != null) { - val downloadKey = putResult.first - requestedDownloads.add(downloadKey) - localBroadcastManager.sendBroadcast(intents.newDownloadIntent(operation, putResult.second)) + files.forEach { file -> + val operation = DownloadFileOperation( + user, + file, + behaviour, + activityName, + packageName, + context, + downloadType + ) + + operation.addDownloadDataTransferProgressListener(this) + operation.addDownloadDataTransferProgressListener(downloadProgressListener) + val (downloadKey, linkedToRemotePath) = pendingDownloads.putIfAbsent( + user?.accountName, + file.remotePath, + operation + ) + + if (downloadKey != null) { + requestedDownloads.add(downloadKey) + localBroadcastManager.sendBroadcast(intents.newDownloadIntent(operation, linkedToRemotePath)) + } } requestedDownloads @@ -176,6 +179,36 @@ class FileDownloadWorker( } } + private fun setUser() { + val accountName = inputData.keyValueMap[USER_NAME] as String + user = accountManager.getUser(accountName).get() + } + + private fun getFiles(): List { + val filesJson = inputData.keyValueMap[FILES] as String? + + return if (filesJson != null) { + val ocFileListType = object : TypeToken>() {}.type + gson.fromJson(filesJson, ocFileListType) + } else { + val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) + listOf(file) + } + } + + private fun getDownloadType(): DownloadType? { + val typeAsString = inputData.keyValueMap[DOWNLOAD_TYPE] as String? + return if (typeAsString != null) { + if (typeAsString == DownloadType.DOWNLOAD.toString()) { + DownloadType.DOWNLOAD + } else { + DownloadType.EXPORT + } + } else { + null + } + } + private fun setWorkerState(user: User?, file: DownloadFileOperation?) { WorkerStateLiveData.instance().setWorkState(WorkerState.Download(user, file)) } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index ee338476397f..f60b7f3000fd 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -24,6 +24,7 @@ import androidx.work.ListenableWorker import com.nextcloud.client.account.User import com.owncloud.android.datamodel.OCFile import com.owncloud.android.operations.DownloadType +import java.util.concurrent.atomic.AtomicBoolean /** * This interface allows to control, schedule and monitor all application @@ -152,7 +153,7 @@ interface BackgroundJobManager { @Suppress("LongParameterList") fun startFileDownloadJob( user: User, - ocFile: OCFile, + file: OCFile, behaviour: String, downloadType: DownloadType?, activityName: String, @@ -160,6 +161,12 @@ interface BackgroundJobManager { conflictUploadId: Long? ) + fun startFolderDownloadJob( + folder: OCFile, + user: User, + files: List + ) + fun startPdfGenerateAndUploadWork(user: User, uploadFolder: String, imagePaths: List, pdfPath: String) fun scheduleTestJob() diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 11a2ab765a25..dc2484c5eb41 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -47,6 +47,7 @@ import com.owncloud.android.operations.DownloadType import java.util.Date import java.util.UUID import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicBoolean import kotlin.reflect.KClass /** @@ -108,6 +109,7 @@ internal class BackgroundJobManagerImpl( const val PERIODIC_BACKUP_INTERVAL_MINUTES = 24 * 60L const val DEFAULT_PERIODIC_JOB_INTERVAL_MINUTES = 15L const val DEFAULT_IMMEDIATE_JOB_DELAY_SEC = 3L + private val gson = Gson() private const val KEEP_LOG_MILLIS = 1000 * 60 * 60 * 24 * 3L @@ -510,61 +512,53 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_FILES_UPLOAD + user.accountName, ExistingWorkPolicy.KEEP, request) } - @Suppress("LongParameterList") - private fun getOneTimeDownloadRequest( - user: User, - file: OCFile, - behaviour: String, - downloadType: DownloadType?, - activityName: String, - packageName: String, - conflictUploadId: Long? - ): OneTimeWorkRequest { - val gson = Gson() + private fun startFileDownloadJobTag(user: User, file: OCFile): String { + return JOB_FILES_DOWNLOAD + user.accountName + file.fileId + } + override fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean { + return workManager.isWorkScheduled(startFileDownloadJobTag(user, file)) + } + + override fun startFolderDownloadJob(folder: OCFile, user: User, files: List) { val data = workDataOf( FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FILE to gson.toJson(file), - FileDownloadWorker.BEHAVIOUR to behaviour, - FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), - FileDownloadWorker.ACTIVITY_NAME to activityName, - FileDownloadWorker.PACKAGE_NAME to packageName, - FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId + FileDownloadWorker.FILES to gson.toJson(files), + FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString(), ) - return oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) + val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .setInputData(data) .build() - } - - private fun startFileDownloadJobTag(user: User, file: OCFile): String { - return JOB_FILES_DOWNLOAD + user.accountName + file.fileId - } - override fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean { - return workManager.isWorkScheduled(startFileDownloadJobTag(user, file)) + val tag = startFileDownloadJobTag(user, folder) + workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) } override fun startFileDownloadJob( user: User, - ocFile: OCFile, + file: OCFile, behaviour: String, downloadType: DownloadType?, activityName: String, packageName: String, conflictUploadId: Long? ) { - val request = getOneTimeDownloadRequest( - user, - ocFile, - behaviour, - downloadType, - activityName, - packageName, - conflictUploadId + val data = workDataOf( + FileDownloadWorker.USER_NAME to user.accountName, + FileDownloadWorker.FILE to gson.toJson(file), + FileDownloadWorker.BEHAVIOUR to behaviour, + FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), + FileDownloadWorker.ACTIVITY_NAME to activityName, + FileDownloadWorker.PACKAGE_NAME to packageName, + FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId, ) - val tag = startFileDownloadJobTag(user, ocFile) + val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) + .setInputData(data) + .build() + + val tag = startFileDownloadJobTag(user, file) workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) } diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index d6228d3d67bd..7c70b98a9422 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -44,6 +44,7 @@ import java.io.File; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; @@ -438,13 +439,22 @@ private void prepareOpsFromLocalKnowledge() throws OperationCancelledException { } } - private void syncContents() throws OperationCancelledException { startDirectDownloads(); startContentSynchronizations(mFilesToSyncContents); } - private void startDirectDownloads() throws OperationCancelledException { + public static HashMap folderDownloadStatusPair = new HashMap<>(); + + private void startDirectDownloads() { + FileDownloadHelper.Companion.instance().downloadFolder(mLocalFolder, + user, + mFilesForDirectDownload); + + // FIXME cancel request + /* + folderDownloadStatusPair.put(mLocalFolder.getFileId(), true); + for (OCFile file : mFilesForDirectDownload) { synchronized(mCancellationRequested) { if (mCancellationRequested.get()) { @@ -453,6 +463,10 @@ private void startDirectDownloads() throws OperationCancelledException { FileDownloadHelper.Companion.instance().downloadFile(user, file); } } + + folderDownloadStatusPair.replace(mLocalFolder.getFileId(), false); + */ + } /** From a180dcd5b3ca7c776b7ba8ab3a19e2be4dc15480 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 3 Jan 2024 11:52:30 +0100 Subject: [PATCH 139/189] Fix isDownloadingFolder Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 18 +++++++++++------- .../files/downloader/FileDownloadWorker.kt | 12 +++++++++--- .../client/jobs/BackgroundJobManagerImpl.kt | 2 +- .../operations/SynchronizeFolderOperation.java | 2 -- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 24edd309a2d8..370800b6c97f 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -22,6 +22,7 @@ package com.nextcloud.client.files.downloader import com.nextcloud.client.account.User +import com.nextcloud.client.files.downloader.FileDownloadWorker.Companion.folderDownloadStatusPair import com.nextcloud.client.jobs.BackgroundJobManager import com.owncloud.android.MainApp import com.owncloud.android.datamodel.FileDataStorageManager @@ -29,10 +30,8 @@ import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType -import com.owncloud.android.operations.SynchronizeFolderOperation import com.owncloud.android.utils.MimeTypeUtil import java.io.File -import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject class FileDownloadHelper { @@ -62,14 +61,18 @@ class FileDownloadHelper { return false } - return backgroundJobManager.isStartFileDownloadJobScheduled( - user, - file - ) + return if (file.isFolder) { + isFolderDownloading(file) + } else { + backgroundJobManager.isStartFileDownloadJobScheduled( + user, + file + ) + } } private fun isFolderDownloading(folder: OCFile): Boolean { - for ((id, status) in SynchronizeFolderOperation.folderDownloadStatusPair) { + for ((id, status) in folderDownloadStatusPair) { return id == folder.fileId && status } @@ -132,6 +135,7 @@ class FileDownloadHelper { } fun downloadFolder(folder: OCFile, user: User, files: List) { + folderDownloadStatusPair[folder.fileId] = true backgroundJobManager.startFolderDownloadJob(folder, user, files) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 577555680f97..c319d15f52e1 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -46,7 +46,6 @@ import com.owncloud.android.lib.common.OwnCloudAccount import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.OwnCloudClientManagerFactory import com.owncloud.android.lib.common.network.OnDatatransferProgressListener -import com.owncloud.android.lib.common.operations.OperationCancelledException import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode import com.owncloud.android.lib.common.utils.Log_OC @@ -55,11 +54,10 @@ import com.owncloud.android.operations.DownloadType import com.owncloud.android.utils.theme.ViewThemeUtils import java.util.AbstractList import java.util.Vector -import java.util.concurrent.atomic.AtomicBoolean @Suppress("LongParameterList") class FileDownloadWorker( - private val viewThemeUtils: ViewThemeUtils, + viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, private val uploadsStorageManager: UploadsStorageManager, private var localBroadcastManager: LocalBroadcastManager, @@ -70,6 +68,9 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName + var folderDownloadStatusPair = HashMap() + + const val FOLDER_ID = "FOLDER_ID" const val USER_NAME = "USER" const val FILE = "FILE" const val FILES = "FILES" @@ -214,6 +215,11 @@ class FileDownloadWorker( } private fun setIdleWorkerState() { + val folderId = inputData.keyValueMap[FOLDER_ID] as Long? + folderId?.let { + folderDownloadStatusPair.remove(folderId) + } + WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index dc2484c5eb41..c89cc4176ab1 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -47,7 +47,6 @@ import com.owncloud.android.operations.DownloadType import java.util.Date import java.util.UUID import java.util.concurrent.TimeUnit -import java.util.concurrent.atomic.AtomicBoolean import kotlin.reflect.KClass /** @@ -523,6 +522,7 @@ internal class BackgroundJobManagerImpl( override fun startFolderDownloadJob(folder: OCFile, user: User, files: List) { val data = workDataOf( FileDownloadWorker.USER_NAME to user.accountName, + FileDownloadWorker.FOLDER_ID to folder.fileId, FileDownloadWorker.FILES to gson.toJson(files), FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString(), ) diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index 7c70b98a9422..03e5728868d7 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -44,7 +44,6 @@ import java.io.File; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; @@ -444,7 +443,6 @@ private void syncContents() throws OperationCancelledException { startContentSynchronizations(mFilesToSyncContents); } - public static HashMap folderDownloadStatusPair = new HashMap<>(); private void startDirectDownloads() { FileDownloadHelper.Companion.instance().downloadFolder(mLocalFolder, From 157d1864b362c2491953bfe70457dc79fa37dc14 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 3 Jan 2024 14:06:18 +0100 Subject: [PATCH 140/189] Fix cancelAllDownloads Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 5 ++++ .../files/downloader/FileDownloadWorker.kt | 28 +++++++++++++++---- .../client/jobs/BackgroundJobManager.kt | 1 - .../client/jobs/BackgroundJobManagerImpl.kt | 4 +-- .../SynchronizeFolderOperation.java | 17 ----------- 5 files changed, 29 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 370800b6c97f..fea0cc61e9a5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -22,7 +22,9 @@ package com.nextcloud.client.files.downloader import com.nextcloud.client.account.User +import com.nextcloud.client.files.downloader.FileDownloadWorker.Companion.cancelAllDownloads import com.nextcloud.client.files.downloader.FileDownloadWorker.Companion.folderDownloadStatusPair +import com.nextcloud.client.files.downloader.FileDownloadWorker.Companion.removePendingDownload import com.nextcloud.client.jobs.BackgroundJobManager import com.owncloud.android.MainApp import com.owncloud.android.datamodel.FileDataStorageManager @@ -81,6 +83,7 @@ class FileDownloadHelper { fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return + cancelAllDownloads() backgroundJobManager.cancelFilesDownloadJob(user, file) } @@ -92,6 +95,8 @@ class FileDownloadHelper { currentDownload.cancel() } + + removePendingDownload(accountName) } fun saveFile( diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index c319d15f52e1..f4dcbb4ac1fe 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -24,6 +24,7 @@ package com.nextcloud.client.files.downloader import android.accounts.Account import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener +import android.app.NotificationManager import android.app.PendingIntent import android.content.Context import androidx.core.util.component1 @@ -38,6 +39,8 @@ import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional import com.nextcloud.model.WorkerState import com.nextcloud.model.WorkerStateLiveData +import com.owncloud.android.MainApp +import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager @@ -57,7 +60,7 @@ import java.util.Vector @Suppress("LongParameterList") class FileDownloadWorker( - viewThemeUtils: ViewThemeUtils, + private val viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, private val uploadsStorageManager: UploadsStorageManager, private var localBroadcastManager: LocalBroadcastManager, @@ -93,6 +96,24 @@ class FileDownloadWorker( fun getDownloadFinishMessage(): String { return FileDownloadWorker::class.java.name + "DOWNLOAD_FINISH" } + + private val pendingDownloads = IndexedForest() + + fun removePendingDownload(accountName: String?) { + pendingDownloads.remove(accountName) + } + + fun cancelAllDownloads() { + pendingDownloads.all.forEach { + it.value.payload?.cancel() + } + + val notificationManager = + MainApp.getAppContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + notificationManager.cancel(R.string.downloader_download_in_progress_ticker) + + pendingDownloads.all.clear() + } } private var currentDownload: DownloadFileOperation? = null @@ -100,7 +121,6 @@ class FileDownloadWorker( private var lastPercent = 0 private val intents = FileDownloadIntents(context) private val notificationManager = DownloadNotificationManager(context, viewThemeUtils) - private val pendingDownloads = IndexedForest() private var downloadProgressListener = FileDownloadProgressListener() private var currentUser = Optional.empty() private var storageManager: FileDataStorageManager? = null @@ -266,10 +286,6 @@ class FileDownloadWorker( } } - private fun removePendingDownload(accountName: String?) { - pendingDownloads.remove(accountName) - } - private fun notifyDownloadStart(download: DownloadFileOperation) { lastPercent = 0 diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index f60b7f3000fd..cc29456db280 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -24,7 +24,6 @@ import androidx.work.ListenableWorker import com.nextcloud.client.account.User import com.owncloud.android.datamodel.OCFile import com.owncloud.android.operations.DownloadType -import java.util.concurrent.atomic.AtomicBoolean /** * This interface allows to control, schedule and monitor all application diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index c89cc4176ab1..735270490574 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -524,7 +524,7 @@ internal class BackgroundJobManagerImpl( FileDownloadWorker.USER_NAME to user.accountName, FileDownloadWorker.FOLDER_ID to folder.fileId, FileDownloadWorker.FILES to gson.toJson(files), - FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString(), + FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() ) val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) @@ -551,7 +551,7 @@ internal class BackgroundJobManagerImpl( FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), FileDownloadWorker.ACTIVITY_NAME to activityName, FileDownloadWorker.PACKAGE_NAME to packageName, - FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId, + FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId ) val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index 03e5728868d7..ec65a4cc7e3b 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -448,23 +448,6 @@ private void startDirectDownloads() { FileDownloadHelper.Companion.instance().downloadFolder(mLocalFolder, user, mFilesForDirectDownload); - - // FIXME cancel request - /* - folderDownloadStatusPair.put(mLocalFolder.getFileId(), true); - - for (OCFile file : mFilesForDirectDownload) { - synchronized(mCancellationRequested) { - if (mCancellationRequested.get()) { - throw new OperationCancelledException(); - } - FileDownloadHelper.Companion.instance().downloadFile(user, file); - } - } - - folderDownloadStatusPair.replace(mLocalFolder.getFileId(), false); - */ - } /** From ac552c5cde8515cca8f6955b4b9ddf4baa9397ce Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 3 Jan 2024 16:01:48 +0100 Subject: [PATCH 141/189] Fix worker tag Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 17 +----- .../files/downloader/FileDownloadWorker.kt | 54 +++++++++++-------- .../client/jobs/BackgroundJobManagerImpl.kt | 11 ++-- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index fea0cc61e9a5..c1dce3cac56d 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -22,9 +22,6 @@ package com.nextcloud.client.files.downloader import com.nextcloud.client.account.User -import com.nextcloud.client.files.downloader.FileDownloadWorker.Companion.cancelAllDownloads -import com.nextcloud.client.files.downloader.FileDownloadWorker.Companion.folderDownloadStatusPair -import com.nextcloud.client.files.downloader.FileDownloadWorker.Companion.removePendingDownload import com.nextcloud.client.jobs.BackgroundJobManager import com.owncloud.android.MainApp import com.owncloud.android.datamodel.FileDataStorageManager @@ -64,7 +61,7 @@ class FileDownloadHelper { } return if (file.isFolder) { - isFolderDownloading(file) + FileDownloadWorker.isFolderDownloading(file) } else { backgroundJobManager.isStartFileDownloadJobScheduled( user, @@ -73,17 +70,8 @@ class FileDownloadHelper { } } - private fun isFolderDownloading(folder: OCFile): Boolean { - for ((id, status) in folderDownloadStatusPair) { - return id == folder.fileId && status - } - - return false - } - fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return - cancelAllDownloads() backgroundJobManager.cancelFilesDownloadJob(user, file) } @@ -95,8 +83,6 @@ class FileDownloadHelper { currentDownload.cancel() } - - removePendingDownload(accountName) } fun saveFile( @@ -140,7 +126,6 @@ class FileDownloadHelper { } fun downloadFolder(folder: OCFile, user: User, files: List) { - folderDownloadStatusPair[folder.fileId] = true backgroundJobManager.startFolderDownloadJob(folder, user, files) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index f4dcbb4ac1fe..025f40f6be7d 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -24,7 +24,6 @@ package com.nextcloud.client.files.downloader import android.accounts.Account import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener -import android.app.NotificationManager import android.app.PendingIntent import android.content.Context import androidx.core.util.component1 @@ -39,8 +38,6 @@ import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional import com.nextcloud.model.WorkerState import com.nextcloud.model.WorkerStateLiveData -import com.owncloud.android.MainApp -import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager @@ -71,7 +68,7 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName - var folderDownloadStatusPair = HashMap() + private var folderDownloadStatusPair = HashMap() const val FOLDER_ID = "FOLDER_ID" const val USER_NAME = "USER" @@ -89,6 +86,14 @@ class FileDownloadWorker( const val EXTRA_LINKED_TO_PATH = "LINKED_TO" const val ACCOUNT_NAME = "ACCOUNT_NAME" + fun isFolderDownloading(folder: OCFile): Boolean { + for ((id, status) in folderDownloadStatusPair) { + return id == folder.fileId && status + } + + return false + } + fun getDownloadAddedMessage(): String { return FileDownloadWorker::class.java.name + "DOWNLOAD_ADDED" } @@ -96,24 +101,6 @@ class FileDownloadWorker( fun getDownloadFinishMessage(): String { return FileDownloadWorker::class.java.name + "DOWNLOAD_FINISH" } - - private val pendingDownloads = IndexedForest() - - fun removePendingDownload(accountName: String?) { - pendingDownloads.remove(accountName) - } - - fun cancelAllDownloads() { - pendingDownloads.all.forEach { - it.value.payload?.cancel() - } - - val notificationManager = - MainApp.getAppContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - notificationManager.cancel(R.string.downloader_download_in_progress_ticker) - - pendingDownloads.all.clear() - } } private var currentDownload: DownloadFileOperation? = null @@ -127,6 +114,7 @@ class FileDownloadWorker( private var downloadClient: OwnCloudClient? = null private var user: User? = null private val gson = Gson() + private val pendingDownloads = IndexedForest() @Suppress("TooGenericExceptionCaught") override fun doWork(): Result { @@ -151,7 +139,13 @@ class FileDownloadWorker( } override fun onStopped() { + Log_OC.e(TAG, "FilesDownloadWorker stopped") + + cancelAllDownloads() + notificationManager.dismissDownloadInProgressNotification() + removePendingDownload(currentDownload?.user?.accountName) setIdleWorkerState() + super.onStopped() } @@ -200,6 +194,17 @@ class FileDownloadWorker( } } + private fun removePendingDownload(accountName: String?) { + pendingDownloads.remove(accountName) + } + + private fun cancelAllDownloads() { + pendingDownloads.all.forEach { + it.value.payload?.cancel() + } + pendingDownloads.all.clear() + } + private fun setUser() { val accountName = inputData.keyValueMap[USER_NAME] as String user = accountManager.getUser(accountName).get() @@ -231,6 +236,11 @@ class FileDownloadWorker( } private fun setWorkerState(user: User?, file: DownloadFileOperation?) { + val folderId = inputData.keyValueMap[FOLDER_ID] as Long? + folderId?.let { + folderDownloadStatusPair[folderId] = true + } + WorkerStateLiveData.instance().setWorkState(WorkerState.Download(user, file)) } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 735270490574..caf4e4fd0bf3 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -527,12 +527,15 @@ internal class BackgroundJobManagerImpl( FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() ) + val tag = startFileDownloadJobTag(user, folder) + val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) + .addTag(tag) .setInputData(data) .build() - val tag = startFileDownloadJobTag(user, folder) - workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) + workManager + .enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) } override fun startFileDownloadJob( @@ -554,11 +557,13 @@ internal class BackgroundJobManagerImpl( FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId ) + val tag = startFileDownloadJobTag(user, file) + val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) + .addTag(tag) .setInputData(data) .build() - val tag = startFileDownloadJobTag(user, file) workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) } From c525ed51c20d8fc06c58d94b637d7d3494a673d3 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 3 Jan 2024 16:09:39 +0100 Subject: [PATCH 142/189] Fix code analytics Signed-off-by: alperozturk --- .../com/nextcloud/client/files/downloader/FileDownloadWorker.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 025f40f6be7d..ffd907129fee 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -55,7 +55,7 @@ import com.owncloud.android.utils.theme.ViewThemeUtils import java.util.AbstractList import java.util.Vector -@Suppress("LongParameterList") +@Suppress("LongParameterList", "TooManyFunctions") class FileDownloadWorker( private val viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, From 838439571d8aa7971aa94b4452d3dbf1f495f6b9 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 4 Jan 2024 09:22:06 +0100 Subject: [PATCH 143/189] Fix isDownloading Folder Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 12 ++++------- .../files/downloader/FileDownloadWorker.kt | 20 ------------------- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index c1dce3cac56d..9df9157b4b23 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -60,14 +60,10 @@ class FileDownloadHelper { return false } - return if (file.isFolder) { - FileDownloadWorker.isFolderDownloading(file) - } else { - backgroundJobManager.isStartFileDownloadJobScheduled( - user, - file - ) - } + return backgroundJobManager.isStartFileDownloadJobScheduled( + user, + file + ) } fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index ffd907129fee..c6c4eae88ebc 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -68,8 +68,6 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName - private var folderDownloadStatusPair = HashMap() - const val FOLDER_ID = "FOLDER_ID" const val USER_NAME = "USER" const val FILE = "FILE" @@ -86,14 +84,6 @@ class FileDownloadWorker( const val EXTRA_LINKED_TO_PATH = "LINKED_TO" const val ACCOUNT_NAME = "ACCOUNT_NAME" - fun isFolderDownloading(folder: OCFile): Boolean { - for ((id, status) in folderDownloadStatusPair) { - return id == folder.fileId && status - } - - return false - } - fun getDownloadAddedMessage(): String { return FileDownloadWorker::class.java.name + "DOWNLOAD_ADDED" } @@ -236,20 +226,10 @@ class FileDownloadWorker( } private fun setWorkerState(user: User?, file: DownloadFileOperation?) { - val folderId = inputData.keyValueMap[FOLDER_ID] as Long? - folderId?.let { - folderDownloadStatusPair[folderId] = true - } - WorkerStateLiveData.instance().setWorkState(WorkerState.Download(user, file)) } private fun setIdleWorkerState() { - val folderId = inputData.keyValueMap[FOLDER_ID] as Long? - folderId?.let { - folderDownloadStatusPair.remove(folderId) - } - WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } From 9f1ff12f46052a3f32262ec95c29d1fee98f1553 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 12:57:23 +0100 Subject: [PATCH 144/189] Rebase master Signed-off-by: alperozturk --- .../downloader/DownloadNotificationManager.kt | 21 ++++++++++++++++ .../files/downloader/FileDownloadWorker.kt | 24 ++++++++++++++++--- .../client/jobs/BackgroundJobManagerImpl.kt | 2 +- .../ui/activity/FileDisplayActivity.java | 1 - app/src/main/res/values/strings.xml | 7 +----- 5 files changed, 44 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 1457e603fb8e..a1083e537019 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -53,6 +53,7 @@ class DownloadNotificationManager(private val context: Context, private val view setContentText(context.resources.getString(R.string.worker_download)) setSmallIcon(R.drawable.notification_icon) setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) } @@ -117,6 +118,26 @@ class DownloadNotificationManager(private val context: Context, private val view ) } + fun notifyForFolderResult(isAnyOperationFailed: Boolean, folderName: String) { + val notifyId = SecureRandom().nextInt() + val message = if (!isAnyOperationFailed) { + context.getString(R.string.downloader_folder_downloaded, folderName) + } else { + context.getString(R.string.downloader_folder_download_failed, folderName) + } + + notificationBuilder.run { + setContentText(message) + notificationManager.notify(notifyId, this.build()) + } + + NotificationUtils.cancelWithDelay( + notificationManager, + notifyId, + 2000 + ) + } + private fun getResultText(result: RemoteOperationResult<*>, download: DownloadFileOperation): String { return if (result.isSuccess) { download.file.fileName diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index c6c4eae88ebc..b89dbfd792ab 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -57,7 +57,7 @@ import java.util.Vector @Suppress("LongParameterList", "TooManyFunctions") class FileDownloadWorker( - private val viewThemeUtils: ViewThemeUtils, + viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, private val uploadsStorageManager: UploadsStorageManager, private var localBroadcastManager: LocalBroadcastManager, @@ -68,7 +68,7 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName - const val FOLDER_ID = "FOLDER_ID" + const val FOLDER = "FOLDER" const val USER_NAME = "USER" const val FILE = "FILE" const val FILES = "FILES" @@ -103,6 +103,8 @@ class FileDownloadWorker( private var storageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null private var user: User? = null + private var folder: OCFile? = null + private var isAnyOperationFailed = true private val gson = Gson() private val pendingDownloads = IndexedForest() @@ -119,6 +121,9 @@ class FileDownloadWorker( } setIdleWorkerState() + folder?.let { + notifyForFolderResult(it) + } Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() @@ -139,11 +144,16 @@ class FileDownloadWorker( super.onStopped() } + private fun notifyForFolderResult(folder: OCFile) { + notificationManager.notifyForFolderResult(isAnyOperationFailed, folder.fileName) + } + private fun getRequestDownloads(): AbstractList { val files = getFiles() val downloadType = getDownloadType() setUser() + folder = gson.fromJson(inputData.keyValueMap[FOLDER] as? String, OCFile::class.java) ?: null conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val behaviour = inputData.keyValueMap[BEHAVIOUR] as String? ?: "" val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String? ?: "" @@ -312,6 +322,10 @@ class FileDownloadWorker( } private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { + result?.let { + isAnyOperationFailed = !it.isSuccess + } + val removeResult = pendingDownloads.removePayload( currentDownload?.user?.accountName, currentDownload?.remotePath @@ -321,11 +335,13 @@ class FileDownloadWorker( currentDownload?.run { notifyDownloadResult(this, downloadResult) + val downloadFinishedIntent = intents.downloadFinishedIntent( this, downloadResult, removeResult.second ) + localBroadcastManager.sendBroadcast(downloadFinishedIntent) } } @@ -353,7 +369,9 @@ class FileDownloadWorker( setContentIntent(intents.detailsIntent(null), PendingIntent.FLAG_IMMUTABLE) } - notifyForResult(downloadResult, download) + if (folder == null) { + notifyForResult(downloadResult, download) + } } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index caf4e4fd0bf3..fafc632deee4 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -522,7 +522,7 @@ internal class BackgroundJobManagerImpl( override fun startFolderDownloadJob(folder: OCFile, user: User, files: List) { val data = workDataOf( FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FOLDER_ID to folder.fileId, + FileDownloadWorker.FOLDER to gson.toJson(folder), FileDownloadWorker.FILES to gson.toJson(files), FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() ) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index d54374c1c4e0..fa290e500d4f 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1585,7 +1585,6 @@ protected ServiceConnection newTransferenceServiceConnection() { return new ListServiceConnection(); } - // FIXME ServiceConnection will not trigger anymore /** * Defines callbacks for service binding, passed to bindService() */ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fc427dd5516f..2ad28653e254 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -168,19 +168,14 @@ Waiting to upload %1$s (%2$d) Downloading… - Downloads are completed - %1$d%% %2$s %1$d%% Downloading %2$s Downloaded %1$s downloaded Download failed Could not download %1$s Not downloaded yet - %s file download cancelled - Error occurred while downloading %s file + Error occurred while downloading %s folder %s folder successfully downloaded - %s file successfully downloaded - Unexpected error occurred while downloading files Download failed, log in again Choose account Switch account From 1df82a7302a187b3f225f161e645a96cd8a69f09 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 4 Jan 2024 10:43:19 +0100 Subject: [PATCH 145/189] Fix code analytics Signed-off-by: alperozturk --- .../downloader/DownloadNotificationManager.kt | 80 +++++++++++-------- .../files/downloader/FileDownloadWorker.kt | 4 +- 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index a1083e537019..eddfed9f3147 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -32,6 +32,7 @@ import androidx.core.app.NotificationCompat import com.nextcloud.client.account.User import com.owncloud.android.R import com.owncloud.android.authentication.AuthenticatorActivity +import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.resources.files.FileUtils import com.owncloud.android.operations.DownloadFileOperation @@ -87,7 +88,7 @@ class DownloadNotificationManager(private val context: Context, private val view downloadResult: RemoteOperationResult<*>, needsToUpdateCredentials: Boolean ) { - val tickerId = getTickerId(downloadResult.isSuccess, needsToUpdateCredentials) + val tickerId = getTickerId(downloadResult.isSuccess, needsToUpdateCredentials, null, null) notificationBuilder .setTicker(context.getString(tickerId)) @@ -98,12 +99,17 @@ class DownloadNotificationManager(private val context: Context, private val view } @Suppress("MagicNumber") - fun notifyForResult(result: RemoteOperationResult<*>, download: DownloadFileOperation) { + fun notifyForResult( + result: RemoteOperationResult<*>?, + download: DownloadFileOperation?, + folder: OCFile?, + isAnyOperationFailed: Boolean? + ) { dismissDownloadInProgressNotification() - val tickerId = getTickerId(result.isSuccess, null) + val tickerId = getTickerId(result?.isSuccess, null, folder, isAnyOperationFailed) val notifyId = SecureRandom().nextInt() - val resultText = getResultText(result, download) + val resultText = getResultText(result, download, folder, isAnyOperationFailed) notificationBuilder.run { setTicker(context.getString(tickerId)) @@ -118,47 +124,55 @@ class DownloadNotificationManager(private val context: Context, private val view ) } - fun notifyForFolderResult(isAnyOperationFailed: Boolean, folderName: String) { - val notifyId = SecureRandom().nextInt() - val message = if (!isAnyOperationFailed) { - context.getString(R.string.downloader_folder_downloaded, folderName) + private fun getResultText( + result: RemoteOperationResult<*>?, + download: DownloadFileOperation?, + folder: OCFile?, + isAnyOperationFailed: Boolean? + ): String { + return folder?.let { + getFolderResultText(isAnyOperationFailed, it) + } ?: if (result?.isSuccess == true) { + download?.file?.fileName ?: "" } else { - context.getString(R.string.downloader_folder_download_failed, folderName) + ErrorMessageAdapter.getErrorCauseMessage(result, download, context.resources) } + } - notificationBuilder.run { - setContentText(message) - notificationManager.notify(notifyId, this.build()) + private fun getFolderResultText(isAnyOperationFailed: Boolean?, folder: OCFile): String { + return if (isAnyOperationFailed == false) { + context.getString(R.string.downloader_folder_downloaded, folder.fileName) + } else { + context.getString(R.string.downloader_folder_download_failed, folder.fileName) } + } - NotificationUtils.cancelWithDelay( - notificationManager, - notifyId, - 2000 - ) + private fun getTickerId( + isSuccess: Boolean?, + needsToUpdateCredentials: Boolean?, + folder: OCFile?, + isAnyOperationFailed: Boolean? + ): Int { + return if (needsToUpdateCredentials == true) { + R.string.downloader_download_failed_credentials_error + } else { + folder?.let { getFolderTickerId(isAnyOperationFailed) } ?: getFileTickerId(isSuccess) + } } - private fun getResultText(result: RemoteOperationResult<*>, download: DownloadFileOperation): String { - return if (result.isSuccess) { - download.file.fileName + private fun getFileTickerId(isSuccess: Boolean?): Int { + return if (isSuccess == true) { + R.string.downloader_download_succeeded_ticker } else { - ErrorMessageAdapter.getErrorCauseMessage( - result, - download, - context.resources - ) + R.string.downloader_download_failed_ticker } } - private fun getTickerId(isSuccess: Boolean, needsToUpdateCredentials: Boolean?): Int { - return if (needsToUpdateCredentials == true) { - R.string.downloader_download_failed_credentials_error + private fun getFolderTickerId(isAnyOperationFailed: Boolean?): Int { + return if (isAnyOperationFailed == false) { + R.string.downloader_folder_downloaded } else { - if (isSuccess) { - R.string.downloader_download_succeeded_ticker - } else { - R.string.downloader_download_failed_ticker - } + R.string.downloader_folder_download_failed } } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index b89dbfd792ab..45a731b92a92 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -145,7 +145,7 @@ class FileDownloadWorker( } private fun notifyForFolderResult(folder: OCFile) { - notificationManager.notifyForFolderResult(isAnyOperationFailed, folder.fileName) + notificationManager.notifyForResult(null, null, folder, isAnyOperationFailed) } private fun getRequestDownloads(): AbstractList { @@ -370,7 +370,7 @@ class FileDownloadWorker( } if (folder == null) { - notifyForResult(downloadResult, download) + notifyForResult(downloadResult, download, null, null) } } } From cb40aaf437d580b25ae6c2771f9801d1a40b2827 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 4 Jan 2024 17:00:37 +0100 Subject: [PATCH 146/189] Add capability to track multiple download workers Signed-off-by: alperozturk --- .../files/downloader/FileDownloadWorker.kt | 24 +++++++----- .../client/jobs/BackgroundJobManagerImpl.kt | 5 ++- ...Data.kt => DownloadWorkerStateLiveData.kt} | 24 +++++++++--- .../java/com/nextcloud/model/WorkerState.kt | 5 +-- .../utils/extensions/ContextExtensions.kt | 15 ++++++++ .../ui/activity/FileDisplayActivity.java | 11 +++--- .../ui/activity/ManageAccountsActivity.java | 37 +++++++++++-------- .../android/ui/adapter/GalleryAdapter.kt | 1 + .../android/ui/adapter/OCFileListDelegate.kt | 20 +++++++++- .../ui/preview/PreviewImageActivity.java | 11 +++--- 10 files changed, 102 insertions(+), 51 deletions(-) rename app/src/main/java/com/nextcloud/model/{WorkerStateLiveData.kt => DownloadWorkerStateLiveData.kt} (59%) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 45a731b92a92..8b0f3563ddd6 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -36,8 +36,8 @@ import com.google.gson.reflect.TypeToken import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional -import com.nextcloud.model.WorkerState -import com.nextcloud.model.WorkerStateLiveData +import com.nextcloud.model.DownloadWorkerState +import com.nextcloud.model.DownloadWorkerStateLiveData import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager @@ -68,6 +68,7 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName + const val WORKER_TAG = "WORKER_TAG" const val FOLDER = "FOLDER" const val USER_NAME = "USER" const val FILE = "FILE" @@ -106,6 +107,7 @@ class FileDownloadWorker( private var folder: OCFile? = null private var isAnyOperationFailed = true private val gson = Gson() + private var workerTag: String? = null private val pendingDownloads = IndexedForest() @Suppress("TooGenericExceptionCaught") @@ -144,6 +146,15 @@ class FileDownloadWorker( super.onStopped() } + private fun setWorkerState(user: User?, file: DownloadFileOperation?) { + val worker = DownloadWorkerState(workerTag ?: "", user, file) + DownloadWorkerStateLiveData.instance().addWorker(worker) + } + + private fun setIdleWorkerState() { + DownloadWorkerStateLiveData.instance().removeWorker(workerTag ?: "") + } + private fun notifyForFolderResult(folder: OCFile) { notificationManager.notifyForResult(null, null, folder, isAnyOperationFailed) } @@ -153,6 +164,7 @@ class FileDownloadWorker( val downloadType = getDownloadType() setUser() + workerTag = inputData.keyValueMap[WORKER_TAG] as String? ?: "" folder = gson.fromJson(inputData.keyValueMap[FOLDER] as? String, OCFile::class.java) ?: null conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? val behaviour = inputData.keyValueMap[BEHAVIOUR] as String? ?: "" @@ -235,14 +247,6 @@ class FileDownloadWorker( } } - private fun setWorkerState(user: User?, file: DownloadFileOperation?) { - WorkerStateLiveData.instance().setWorkState(WorkerState.Download(user, file)) - } - - private fun setIdleWorkerState() { - WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) - } - private fun addAccountUpdateListener() { val am = AccountManager.get(context) am.addOnAccountsUpdatedListener(this, null, false) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index fafc632deee4..21cc9f7adeda 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -547,7 +547,10 @@ internal class BackgroundJobManagerImpl( packageName: String, conflictUploadId: Long? ) { + val tag = startFileDownloadJobTag(user, file) + val data = workDataOf( + FileDownloadWorker.WORKER_TAG to tag, FileDownloadWorker.USER_NAME to user.accountName, FileDownloadWorker.FILE to gson.toJson(file), FileDownloadWorker.BEHAVIOUR to behaviour, @@ -557,8 +560,6 @@ internal class BackgroundJobManagerImpl( FileDownloadWorker.CONFLICT_UPLOAD_ID to conflictUploadId ) - val tag = startFileDownloadJobTag(user, file) - val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .addTag(tag) .setInputData(data) diff --git a/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt b/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt similarity index 59% rename from app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt rename to app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt index 54fd35f4d702..5dcd1ccb687e 100644 --- a/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt +++ b/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt @@ -23,18 +23,30 @@ package com.nextcloud.model import androidx.lifecycle.LiveData -class WorkerStateLiveData private constructor() : LiveData() { +class DownloadWorkerStateLiveData private constructor() : LiveData>() { - fun setWorkState(state: WorkerState) { - postValue(state) + private var workers: ArrayList = arrayListOf() + + 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: WorkerStateLiveData? = null + private var instance: DownloadWorkerStateLiveData? = null - fun instance(): WorkerStateLiveData { + fun instance(): DownloadWorkerStateLiveData { return instance ?: synchronized(this) { - instance ?: WorkerStateLiveData().also { instance = it } + instance ?: DownloadWorkerStateLiveData().also { instance = it } } } } diff --git a/app/src/main/java/com/nextcloud/model/WorkerState.kt b/app/src/main/java/com/nextcloud/model/WorkerState.kt index 5bca9bb62b80..b746154fb60b 100644 --- a/app/src/main/java/com/nextcloud/model/WorkerState.kt +++ b/app/src/main/java/com/nextcloud/model/WorkerState.kt @@ -24,7 +24,4 @@ package com.nextcloud.model import com.nextcloud.client.account.User import com.owncloud.android.operations.DownloadFileOperation -sealed class WorkerState { - object Idle : WorkerState() - class Download(var user: User?, var currentDownload: DownloadFileOperation?) : WorkerState() -} +data class DownloadWorkerState(var tag: String, var user: User?, var currentDownload: DownloadFileOperation?) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt index 6dc7dde71e2f..955d4eb3d024 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt @@ -24,9 +24,11 @@ package com.nextcloud.utils.extensions import android.annotation.SuppressLint import android.content.BroadcastReceiver import android.content.Context +import android.content.ContextWrapper import android.content.Intent import android.content.IntentFilter import android.os.Build +import androidx.lifecycle.LifecycleOwner import com.owncloud.android.datamodel.ReceiverFlag @SuppressLint("UnspecifiedRegisterReceiverFlag") @@ -37,3 +39,16 @@ fun Context.registerBroadcastReceiver(receiver: BroadcastReceiver?, filter: Inte registerReceiver(receiver, filter) } } + +fun Context.lifecycleOwner(): LifecycleOwner? { + var curContext = this + var maxDepth = 20 + while (maxDepth-- > 0 && curContext !is LifecycleOwner) { + curContext = (curContext as ContextWrapper).baseContext + } + return if (curContext is LifecycleOwner) { + curContext + } else { + null + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index fa290e500d4f..e956c3a85ae7 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -73,8 +73,7 @@ import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.client.utils.IntentUtil; import com.nextcloud.java.util.Optional; -import com.nextcloud.model.WorkerState; -import com.nextcloud.model.WorkerStateLiveData; +import com.nextcloud.model.DownloadWorkerStateLiveData; import com.nextcloud.utils.extensions.BundleExtensionsKt; import com.nextcloud.utils.extensions.IntentExtensionsKt; import com.nextcloud.utils.view.FastScrollUtils; @@ -287,7 +286,7 @@ protected void onCreate(Bundle savedInstanceState) { checkStoragePath(); initSyncBroadcastReceiver(); - observeWorkerState(); + observeDownloadWorkerState(); } @SuppressWarnings("unchecked") @@ -1562,9 +1561,9 @@ public boolean isDrawerIndicatorAvailable() { return isRoot(getCurrentDir()); } - private void observeWorkerState() { - WorkerStateLiveData.Companion.instance().observe(this, state -> { - if (state instanceof WorkerState.Download) { + private void observeDownloadWorkerState() { + DownloadWorkerStateLiveData.Companion.instance().observe(this, state -> { + if (!state.isEmpty()) { Log_OC.d(TAG, "Download worker started"); handleDownloadWorkerState(); } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 955c240d0857..9f378374b6eb 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -37,7 +37,6 @@ 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; @@ -45,8 +44,8 @@ import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.onboarding.FirstRunActivity; import com.nextcloud.java.util.Optional; -import com.nextcloud.model.WorkerState; -import com.nextcloud.model.WorkerStateLiveData; +import com.nextcloud.model.DownloadWorkerState; +import com.nextcloud.model.DownloadWorkerStateLiveData; import com.nextcloud.utils.extensions.BundleExtensionsKt; import com.owncloud.android.MainApp; import com.owncloud.android.R; @@ -115,8 +114,7 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap private ArbitraryDataProvider arbitraryDataProvider; private boolean multipleAccountsSupported; - private String workerAccountName; - private DownloadFileOperation workerCurrentDownload; + private final ArrayList downloadWorkerStates = new ArrayList<>(); @Inject BackgroundJobManager backgroundJobManager; @Inject UserAccountManager accountManager; @@ -165,7 +163,7 @@ protected void onCreate(Bundle savedInstanceState) { recyclerView.setAdapter(userListAdapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); initializeComponentGetters(); - observeWorkerState(); + observeDownloadWorkerState(); } @@ -342,7 +340,7 @@ public void run(AccountManagerFuture future) { mUploaderBinder.cancel(accountName); } - FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); + cancelAllDownloadsForAccount(); } User currentUser = getUserAccountManager().getUser(); @@ -410,6 +408,17 @@ protected ServiceConnection newTransferenceServiceConnection() { return new ManageAccountsServiceConnection(); } + private void cancelAllDownloadsForAccount() { + for (DownloadWorkerState workerState : downloadWorkerStates) { + User currentUser = workerState.getUser(); + DownloadFileOperation currentDownload = workerState.getCurrentDownload(); + + if (currentUser != null && currentDownload != null) { + FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(currentUser.getAccountName(), currentDownload); + } + } + } + private void performAccountRemoval(User user) { // disable account in recycler view for (int i = 0; i < userListAdapter.getItemCount(); i++) { @@ -432,8 +441,7 @@ private void performAccountRemoval(User user) { mUploaderBinder.cancel(user); } - FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); - + cancelAllDownloadsForAccount(); backgroundJobManager.startAccountRemovalJob(user.getAccountName(), false); // immediately select a new account @@ -517,13 +525,10 @@ public void onOptionItemClicked(User user, View view) { } } - private void observeWorkerState() { - WorkerStateLiveData.Companion.instance().observe(this, state -> { - if (state instanceof WorkerState.Download) { - Log_OC.d(TAG, "Download worker started"); - workerAccountName = ((WorkerState.Download) state).getUser().getAccountName(); - workerCurrentDownload = ((WorkerState.Download) state).getCurrentDownload(); - } + private void observeDownloadWorkerState() { + DownloadWorkerStateLiveData.Companion.instance().observe(this, state -> { + Log_OC.d(TAG, "Download worker started"); + downloadWorkerStates.addAll(state); }); } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt index df1e1669e88f..1c8e426f9fc6 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt @@ -31,6 +31,7 @@ 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 diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index e4fef4e2999b..7a204b9b91bd 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -34,7 +34,9 @@ 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.nextcloud.utils.extensions.lifecycleOwner import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -74,6 +76,11 @@ class OCFileListDelegate( fun setHighlightedItem(highlightedItem: OCFile?) { this.highlightedItem = highlightedItem } + private var isDownloading = false + + init { + isDownloading() + } fun isCheckedFile(file: OCFile): Boolean { return checkedFiles.contains(file) @@ -339,13 +346,24 @@ class OCFileListDelegate( } } + // FIXME + private fun isDownloading() { + context.lifecycleOwner()?.let { + DownloadWorkerStateLiveData.instance().observe(it) { downloadWorkerStates -> + downloadWorkerStates.forEach { state -> + isDownloading = FileDownloadHelper.instance().isDownloading(user, state.currentDownload?.file) + } + } + } + } + private fun showLocalFileIndicator(file: OCFile, gridViewHolder: ListGridImageViewHolder) { val operationsServiceBinder = transferServiceGetter.operationsServiceBinder val fileUploaderBinder = transferServiceGetter.fileUploaderBinder val icon: Int? = when { operationsServiceBinder?.isSynchronizing(user, file) == true || - FileDownloadHelper.instance().isDownloading(user, file) || + isDownloading || fileUploaderBinder?.isUploading(user, file) == true -> { // synchronizing, downloading or uploading R.drawable.ic_synchronizing diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 80c07b03d7a7..dcff8e8d4b14 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -41,8 +41,7 @@ import com.nextcloud.client.files.downloader.FileDownloadWorker; import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.java.util.Optional; -import com.nextcloud.model.WorkerState; -import com.nextcloud.model.WorkerStateLiveData; +import com.nextcloud.model.DownloadWorkerStateLiveData; import com.nextcloud.utils.extensions.IntentExtensionsKt; import com.owncloud.android.MainApp; import com.owncloud.android.R; @@ -152,7 +151,7 @@ protected void onCreate(Bundle savedInstanceState) { mRequestWaitingForBinder = false; } - observeWorkerState(); + observeDownloadWorkerState(); } public void toggleActionBarVisibility(boolean hide) { @@ -306,9 +305,9 @@ private void onSynchronizeFileOperationFinish(RemoteOperationResult result) { } } - private void observeWorkerState() { - WorkerStateLiveData.Companion.instance().observe(this, state -> { - if (state instanceof WorkerState.Download) { + private void observeDownloadWorkerState() { + DownloadWorkerStateLiveData.Companion.instance().observe(this, state -> { + if (!state.isEmpty()) { Log_OC.d(TAG, "Download worker started"); isDownloadWorkStarted = true; From 726a9c601a0c2221bc934b23f8684dc638d919c0 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 10:22:36 +0100 Subject: [PATCH 147/189] Fix serializable data limit crash Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 11 ++-- .../files/downloader/FileDownloadWorker.kt | 52 +++++++++++++------ .../client/jobs/BackgroundJobManager.kt | 10 ++-- .../client/jobs/BackgroundJobManagerImpl.kt | 26 +++++----- .../model/DownloadWorkerStateLiveData.kt | 18 +++++++ .../java/com/nextcloud/model/WorkerState.kt | 3 +- .../utils/extensions/ContextExtensions.kt | 15 ------ .../ui/activity/ManageAccountsActivity.java | 10 ++-- .../android/ui/adapter/OCFileListDelegate.kt | 19 +------ 9 files changed, 87 insertions(+), 77 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 9df9157b4b23..247b24249be1 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -62,19 +62,19 @@ class FileDownloadHelper { return backgroundJobManager.isStartFileDownloadJobScheduled( user, - file + file.remotePath ) } fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return - backgroundJobManager.cancelFilesDownloadJob(user, file) + backgroundJobManager.cancelFilesDownloadJob(user, file.remotePath) } fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation) { if (currentDownload.user.nameEquals(accountName)) { currentDownload.file?.let { file -> - backgroundJobManager.cancelFilesDownloadJob(currentDownload.user, file) + backgroundJobManager.cancelFilesDownloadJob(currentDownload.user, file.remotePath) } currentDownload.cancel() @@ -122,7 +122,8 @@ class FileDownloadHelper { } fun downloadFolder(folder: OCFile, user: User, files: List) { - backgroundJobManager.startFolderDownloadJob(folder, user, files) + val filesPath = files.map { it.remotePath } + backgroundJobManager.startFolderDownloadJob(folder.remotePath, user, filesPath) } fun downloadFile(user: User, file: OCFile) { @@ -141,7 +142,7 @@ class FileDownloadHelper { ) { backgroundJobManager.startFileDownloadJob( user, - ocFile, + ocFile.remotePath, behaviour, downloadType, activityName, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 8b0f3563ddd6..b98ceee8c5e9 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -31,8 +31,6 @@ import androidx.core.util.component2 import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.Worker import androidx.work.WorkerParameters -import com.google.gson.Gson -import com.google.gson.reflect.TypeToken import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional @@ -68,11 +66,12 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName + const val FILES_SEPARATOR = "," const val WORKER_TAG = "WORKER_TAG" - const val FOLDER = "FOLDER" + const val FOLDER_PATH = "FOLDER_PATH" const val USER_NAME = "USER" - const val FILE = "FILE" - const val FILES = "FILES" + const val FILE_PATH = "FILE_PATH" + const val FILES_PATH = "FILES_PATH" const val BEHAVIOUR = "BEHAVIOUR" const val DOWNLOAD_TYPE = "DOWNLOAD_TYPE" const val ACTIVITY_NAME = "ACTIVITY_NAME" @@ -102,11 +101,11 @@ class FileDownloadWorker( private var downloadProgressListener = FileDownloadProgressListener() private var currentUser = Optional.empty() private var storageManager: FileDataStorageManager? = null + private var fileDataStorageManager: FileDataStorageManager? = null private var downloadClient: OwnCloudClient? = null private var user: User? = null private var folder: OCFile? = null private var isAnyOperationFailed = true - private val gson = Gson() private var workerTag: String? = null private val pendingDownloads = IndexedForest() @@ -118,6 +117,7 @@ class FileDownloadWorker( notificationManager.init() addAccountUpdateListener() + setWorkerState(user) requestDownloads.forEach { downloadFile(it) } @@ -146,8 +146,8 @@ class FileDownloadWorker( super.onStopped() } - private fun setWorkerState(user: User?, file: DownloadFileOperation?) { - val worker = DownloadWorkerState(workerTag ?: "", user, file) + private fun setWorkerState(user: User?) { + val worker = DownloadWorkerState(workerTag ?: "", user, pendingDownloads) DownloadWorkerStateLiveData.instance().addWorker(worker) } @@ -160,13 +160,14 @@ class FileDownloadWorker( } private fun getRequestDownloads(): AbstractList { + setUser() + setFolder() val files = getFiles() val downloadType = getDownloadType() - setUser() workerTag = inputData.keyValueMap[WORKER_TAG] as String? ?: "" - folder = gson.fromJson(inputData.keyValueMap[FOLDER] as? String, OCFile::class.java) ?: null conflictUploadId = inputData.keyValueMap[CONFLICT_UPLOAD_ID] as Long? + val behaviour = inputData.keyValueMap[BEHAVIOUR] as String? ?: "" val activityName = inputData.keyValueMap[ACTIVITY_NAME] as String? ?: "" val packageName = inputData.keyValueMap[PACKAGE_NAME] as String? ?: "" @@ -220,18 +221,36 @@ class FileDownloadWorker( private fun setUser() { val accountName = inputData.keyValueMap[USER_NAME] as String user = accountManager.getUser(accountName).get() + fileDataStorageManager = FileDataStorageManager(user, context.contentResolver) + } + + private fun setFolder() { + val folderPath = inputData.keyValueMap[FOLDER_PATH] as? String? + if (folderPath != null) { + folder = storageManager?.getFileByEncryptedRemotePath(folderPath) + } } private fun getFiles(): List { - val filesJson = inputData.keyValueMap[FILES] as String? + val result = arrayListOf() - return if (filesJson != null) { - val ocFileListType = object : TypeToken>() {}.type - gson.fromJson(filesJson, ocFileListType) + val filesPath = inputData.keyValueMap[FILES_PATH] as String? + val filesPathList = filesPath?.split(FILES_SEPARATOR) + + if (filesPathList != null) { + filesPathList.forEach { + fileDataStorageManager?.getFileByEncryptedRemotePath(it)?.let { file -> + result.add(file) + } + } } else { - val file = gson.fromJson(inputData.keyValueMap[FILE] as String, OCFile::class.java) - listOf(file) + val remotePath = inputData.keyValueMap[FILE_PATH] as String + fileDataStorageManager?.getFileByEncryptedRemotePath(remotePath)?.let { file -> + result.add(file) + } } + + return result } private fun getDownloadType(): DownloadType? { @@ -261,7 +280,6 @@ class FileDownloadWorker( } Log_OC.e(TAG, "FilesDownloadWorker downloading: $downloadKey") - setWorkerState(user, currentDownload) val isAccountExist = accountManager.exists(currentDownload?.user?.toPlatformAccount()) if (!isAccountExist) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index cc29456db280..4555417de992 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -145,14 +145,14 @@ interface BackgroundJobManager { fun getFileUploads(user: User): LiveData> fun cancelFilesUploadJob(user: User) - fun cancelFilesDownloadJob(user: User, file: OCFile) + fun cancelFilesDownloadJob(user: User, path: String) - fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean + fun isStartFileDownloadJobScheduled(user: User, path: String): Boolean @Suppress("LongParameterList") fun startFileDownloadJob( user: User, - file: OCFile, + filePath: String, behaviour: String, downloadType: DownloadType?, activityName: String, @@ -161,9 +161,9 @@ interface BackgroundJobManager { ) fun startFolderDownloadJob( - folder: OCFile, + folderPath: String, user: User, - files: List + filesPath: List ) fun startPdfGenerateAndUploadWork(user: User, uploadFolder: String, imagePaths: List, pdfPath: String) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 21cc9f7adeda..1540cdd4b95f 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -511,23 +511,23 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_FILES_UPLOAD + user.accountName, ExistingWorkPolicy.KEEP, request) } - private fun startFileDownloadJobTag(user: User, file: OCFile): String { - return JOB_FILES_DOWNLOAD + user.accountName + file.fileId + private fun startFileDownloadJobTag(user: User, path: String): String { + return JOB_FILES_DOWNLOAD + user.accountName + path } - override fun isStartFileDownloadJobScheduled(user: User, file: OCFile): Boolean { - return workManager.isWorkScheduled(startFileDownloadJobTag(user, file)) + override fun isStartFileDownloadJobScheduled(user: User, path: String): Boolean { + return workManager.isWorkScheduled(startFileDownloadJobTag(user, path)) } - override fun startFolderDownloadJob(folder: OCFile, user: User, files: List) { + override fun startFolderDownloadJob(folderPath: String, user: User, filesPath: List) { val data = workDataOf( FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FOLDER to gson.toJson(folder), - FileDownloadWorker.FILES to gson.toJson(files), + FileDownloadWorker.FOLDER_PATH to folderPath, + FileDownloadWorker.FILES_PATH to filesPath.joinToString(FileDownloadWorker.FILES_SEPARATOR), FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() ) - val tag = startFileDownloadJobTag(user, folder) + val tag = startFileDownloadJobTag(user, folderPath) val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .addTag(tag) @@ -540,19 +540,19 @@ internal class BackgroundJobManagerImpl( override fun startFileDownloadJob( user: User, - file: OCFile, + filePath: String, behaviour: String, downloadType: DownloadType?, activityName: String, packageName: String, conflictUploadId: Long? ) { - val tag = startFileDownloadJobTag(user, file) + val tag = startFileDownloadJobTag(user, filePath) val data = workDataOf( FileDownloadWorker.WORKER_TAG to tag, FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FILE to gson.toJson(file), + FileDownloadWorker.FILE_PATH to filePath, FileDownloadWorker.BEHAVIOUR to behaviour, FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), FileDownloadWorker.ACTIVITY_NAME to activityName, @@ -577,8 +577,8 @@ internal class BackgroundJobManagerImpl( workManager.cancelJob(JOB_FILES_UPLOAD, user) } - override fun cancelFilesDownloadJob(user: User, file: OCFile) { - workManager.cancelAllWorkByTag(startFileDownloadJobTag(user, file)) + override fun cancelFilesDownloadJob(user: User, path: String) { + workManager.cancelAllWorkByTag(startFileDownloadJobTag(user, path)) } override fun startPdfGenerateAndUploadWork( diff --git a/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt b/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt index 5dcd1ccb687e..8e1672727723 100644 --- a/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt +++ b/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt @@ -22,11 +22,29 @@ 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>() { private var workers: ArrayList = 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) { diff --git a/app/src/main/java/com/nextcloud/model/WorkerState.kt b/app/src/main/java/com/nextcloud/model/WorkerState.kt index b746154fb60b..ebe2723c1239 100644 --- a/app/src/main/java/com/nextcloud/model/WorkerState.kt +++ b/app/src/main/java/com/nextcloud/model/WorkerState.kt @@ -22,6 +22,7 @@ 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 currentDownload: DownloadFileOperation?) +data class DownloadWorkerState(var tag: String, var user: User?, var pendingDownloads: IndexedForest?) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt index 955d4eb3d024..6dc7dde71e2f 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ContextExtensions.kt @@ -24,11 +24,9 @@ package com.nextcloud.utils.extensions import android.annotation.SuppressLint import android.content.BroadcastReceiver import android.content.Context -import android.content.ContextWrapper import android.content.Intent import android.content.IntentFilter import android.os.Build -import androidx.lifecycle.LifecycleOwner import com.owncloud.android.datamodel.ReceiverFlag @SuppressLint("UnspecifiedRegisterReceiverFlag") @@ -39,16 +37,3 @@ fun Context.registerBroadcastReceiver(receiver: BroadcastReceiver?, filter: Inte registerReceiver(receiver, filter) } } - -fun Context.lifecycleOwner(): LifecycleOwner? { - var curContext = this - var maxDepth = 20 - while (maxDepth-- > 0 && curContext !is LifecycleOwner) { - curContext = (curContext as ContextWrapper).baseContext - } - return if (curContext is LifecycleOwner) { - curContext - } else { - null - } -} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 9f378374b6eb..88b1a9c0f3ba 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -54,6 +54,7 @@ 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; @@ -411,10 +412,13 @@ protected ServiceConnection newTransferenceServiceConnection() { private void cancelAllDownloadsForAccount() { for (DownloadWorkerState workerState : downloadWorkerStates) { User currentUser = workerState.getUser(); - DownloadFileOperation currentDownload = workerState.getCurrentDownload(); + IndexedForest pendingDownloads = workerState.getPendingDownloads(); - if (currentUser != null && currentDownload != null) { - FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(currentUser.getAccountName(), currentDownload); + if (currentUser != null && pendingDownloads != null) { + pendingDownloads.getAll().values().forEach((value) -> { + DownloadFileOperation operation = value.getPayload(); + FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(currentUser.getAccountName(), operation); + }); } } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 7a204b9b91bd..c2dcac7d92c2 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -36,7 +36,6 @@ 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.nextcloud.utils.extensions.lifecycleOwner import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -76,11 +75,6 @@ class OCFileListDelegate( fun setHighlightedItem(highlightedItem: OCFile?) { this.highlightedItem = highlightedItem } - private var isDownloading = false - - init { - isDownloading() - } fun isCheckedFile(file: OCFile): Boolean { return checkedFiles.contains(file) @@ -346,24 +340,13 @@ class OCFileListDelegate( } } - // FIXME - private fun isDownloading() { - context.lifecycleOwner()?.let { - DownloadWorkerStateLiveData.instance().observe(it) { downloadWorkerStates -> - downloadWorkerStates.forEach { state -> - isDownloading = FileDownloadHelper.instance().isDownloading(user, state.currentDownload?.file) - } - } - } - } - private fun showLocalFileIndicator(file: OCFile, gridViewHolder: ListGridImageViewHolder) { val operationsServiceBinder = transferServiceGetter.operationsServiceBinder val fileUploaderBinder = transferServiceGetter.fileUploaderBinder val icon: Int? = when { operationsServiceBinder?.isSynchronizing(user, file) == true || - isDownloading || + DownloadWorkerStateLiveData.instance().isDownloading(user, file) || fileUploaderBinder?.isUploading(user, file) == true -> { // synchronizing, downloading or uploading R.drawable.ic_synchronizing From bb0fae654fcbdf25fe71f0ab8695dd2d327ac119 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 10:36:51 +0100 Subject: [PATCH 148/189] Fix file sync icon Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 10 +++---- .../client/jobs/BackgroundJobManager.kt | 8 +++--- .../client/jobs/BackgroundJobManagerImpl.kt | 27 +++++++++---------- .../model/DownloadWorkerStateLiveData.kt | 2 +- .../android/ui/adapter/OCFileListDelegate.kt | 8 +++++- 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 247b24249be1..24a5b4df7ae5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -62,19 +62,19 @@ class FileDownloadHelper { return backgroundJobManager.isStartFileDownloadJobScheduled( user, - file.remotePath + file ) } fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return - backgroundJobManager.cancelFilesDownloadJob(user, file.remotePath) + backgroundJobManager.cancelFilesDownloadJob(user, file) } fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation) { if (currentDownload.user.nameEquals(accountName)) { currentDownload.file?.let { file -> - backgroundJobManager.cancelFilesDownloadJob(currentDownload.user, file.remotePath) + backgroundJobManager.cancelFilesDownloadJob(currentDownload.user, file) } currentDownload.cancel() @@ -123,7 +123,7 @@ class FileDownloadHelper { fun downloadFolder(folder: OCFile, user: User, files: List) { val filesPath = files.map { it.remotePath } - backgroundJobManager.startFolderDownloadJob(folder.remotePath, user, filesPath) + backgroundJobManager.startFolderDownloadJob(folder, user, filesPath) } fun downloadFile(user: User, file: OCFile) { @@ -142,7 +142,7 @@ class FileDownloadHelper { ) { backgroundJobManager.startFileDownloadJob( user, - ocFile.remotePath, + ocFile, behaviour, downloadType, activityName, diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 4555417de992..0a37bc0585da 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -145,14 +145,14 @@ interface BackgroundJobManager { fun getFileUploads(user: User): LiveData> fun cancelFilesUploadJob(user: User) - fun cancelFilesDownloadJob(user: User, path: String) + fun cancelFilesDownloadJob(user: User, ocFile: OCFile) - fun isStartFileDownloadJobScheduled(user: User, path: String): Boolean + fun isStartFileDownloadJobScheduled(user: User, ocFile: OCFile): Boolean @Suppress("LongParameterList") fun startFileDownloadJob( user: User, - filePath: String, + file: OCFile, behaviour: String, downloadType: DownloadType?, activityName: String, @@ -161,7 +161,7 @@ interface BackgroundJobManager { ) fun startFolderDownloadJob( - folderPath: String, + folder: OCFile, user: User, filesPath: List ) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 1540cdd4b95f..f469376aac78 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -42,6 +42,7 @@ 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 @@ -108,7 +109,6 @@ internal class BackgroundJobManagerImpl( const val PERIODIC_BACKUP_INTERVAL_MINUTES = 24 * 60L const val DEFAULT_PERIODIC_JOB_INTERVAL_MINUTES = 15L const val DEFAULT_IMMEDIATE_JOB_DELAY_SEC = 3L - private val gson = Gson() private const val KEEP_LOG_MILLIS = 1000 * 60 * 60 * 24 * 3L @@ -500,7 +500,6 @@ internal class BackgroundJobManagerImpl( workManager.enqueue(request) } - override fun startFilesUploadJob(user: User) { val data = workDataOf(FilesUploadWorker.ACCOUNT to user.accountName) @@ -511,23 +510,23 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_FILES_UPLOAD + user.accountName, ExistingWorkPolicy.KEEP, request) } - private fun startFileDownloadJobTag(user: User, path: String): String { - return JOB_FILES_DOWNLOAD + user.accountName + path + private fun startFileDownloadJobTag(user: User, ocFile: OCFile): String { + return JOB_FILES_DOWNLOAD + user.accountName + ocFile.fileId } - override fun isStartFileDownloadJobScheduled(user: User, path: String): Boolean { - return workManager.isWorkScheduled(startFileDownloadJobTag(user, path)) + override fun isStartFileDownloadJobScheduled(user: User, ocFile: OCFile): Boolean { + return workManager.isWorkScheduled(startFileDownloadJobTag(user, ocFile)) } - override fun startFolderDownloadJob(folderPath: String, user: User, filesPath: List) { + override fun startFolderDownloadJob(folder: OCFile, user: User, filesPath: List) { val data = workDataOf( FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FOLDER_PATH to folderPath, + FileDownloadWorker.FOLDER_PATH to folder.remotePath, FileDownloadWorker.FILES_PATH to filesPath.joinToString(FileDownloadWorker.FILES_SEPARATOR), FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() ) - val tag = startFileDownloadJobTag(user, folderPath) + val tag = startFileDownloadJobTag(user, folder) val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .addTag(tag) @@ -540,19 +539,19 @@ internal class BackgroundJobManagerImpl( override fun startFileDownloadJob( user: User, - filePath: String, + file: OCFile, behaviour: String, downloadType: DownloadType?, activityName: String, packageName: String, conflictUploadId: Long? ) { - val tag = startFileDownloadJobTag(user, filePath) + val tag = startFileDownloadJobTag(user, file) val data = workDataOf( FileDownloadWorker.WORKER_TAG to tag, FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FILE_PATH to filePath, + FileDownloadWorker.FILE_PATH to file.remotePath, FileDownloadWorker.BEHAVIOUR to behaviour, FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), FileDownloadWorker.ACTIVITY_NAME to activityName, @@ -577,8 +576,8 @@ internal class BackgroundJobManagerImpl( workManager.cancelJob(JOB_FILES_UPLOAD, user) } - override fun cancelFilesDownloadJob(user: User, path: String) { - workManager.cancelAllWorkByTag(startFileDownloadJobTag(user, path)) + override fun cancelFilesDownloadJob(user: User, ocFile: OCFile) { + workManager.cancelAllWorkByTag(startFileDownloadJobTag(user, ocFile)) } override fun startPdfGenerateAndUploadWork( diff --git a/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt b/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt index 8e1672727723..a3a97921c1d8 100644 --- a/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt +++ b/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt @@ -25,7 +25,7 @@ import androidx.lifecycle.LiveData import com.nextcloud.client.account.User import com.owncloud.android.datamodel.OCFile -class DownloadWorkerStateLiveData private constructor() : LiveData>() { +class DownloadWorkerStateLiveData private constructor(): LiveData>() { private var workers: ArrayList = arrayListOf() diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index c2dcac7d92c2..1ceecc16f172 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -344,9 +344,15 @@ 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 || - DownloadWorkerStateLiveData.instance().isDownloading(user, file) || + isDownloading || fileUploaderBinder?.isUploading(user, file) == true -> { // synchronizing, downloading or uploading R.drawable.ic_synchronizing From de4f67374021eba884168b72ab8f871bf65628d8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 11:06:04 +0100 Subject: [PATCH 149/189] Fix tracking current download status Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 2 +- .../files/downloader/FileDownloadWorker.kt | 25 ++++--- .../client/jobs/BackgroundJobManagerImpl.kt | 3 - .../model/DownloadWorkerStateLiveData.kt | 71 ------------------- .../java/com/nextcloud/model/WorkerState.kt | 6 +- .../nextcloud/model/WorkerStateLiveData.kt | 41 +++++++++++ .../ui/activity/FileDisplayActivity.java | 7 +- .../ui/activity/ManageAccountsActivity.java | 41 +++++------ .../android/ui/adapter/GalleryAdapter.kt | 1 - .../android/ui/adapter/OCFileListDelegate.kt | 16 ++--- .../ui/preview/PreviewImageActivity.java | 7 +- 11 files changed, 92 insertions(+), 128 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt create mode 100644 app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 24a5b4df7ae5..e599755727ef 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -63,7 +63,7 @@ class FileDownloadHelper { return backgroundJobManager.isStartFileDownloadJobScheduled( user, file - ) + ) || FileDownloadWorker.isDownloading(user, file) } fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index b98ceee8c5e9..8705a6a3b2f5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -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() 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() @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() { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index f469376aac78..8b4c2ef6ff48 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -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, diff --git a/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt b/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt deleted file mode 100644 index a3a97921c1d8..000000000000 --- a/app/src/main/java/com/nextcloud/model/DownloadWorkerStateLiveData.kt +++ /dev/null @@ -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 . - */ - -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>() { - - private var workers: ArrayList = 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 } - } - } - } -} diff --git a/app/src/main/java/com/nextcloud/model/WorkerState.kt b/app/src/main/java/com/nextcloud/model/WorkerState.kt index ebe2723c1239..5bca9bb62b80 100644 --- a/app/src/main/java/com/nextcloud/model/WorkerState.kt +++ b/app/src/main/java/com/nextcloud/model/WorkerState.kt @@ -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?) +sealed class WorkerState { + object Idle : WorkerState() + class Download(var user: User?, var currentDownload: DownloadFileOperation?) : WorkerState() +} diff --git a/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt b/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt new file mode 100644 index 000000000000..54fd35f4d702 --- /dev/null +++ b/app/src/main/java/com/nextcloud/model/WorkerStateLiveData.kt @@ -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 . + */ + +package com.nextcloud.model + +import androidx.lifecycle.LiveData + +class WorkerStateLiveData private constructor() : LiveData() { + + 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 } + } + } + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index e956c3a85ae7..43d7a3a740a4 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -73,7 +73,8 @@ 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 boolean isDrawerIndicatorAvailable() { } 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(); } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 88b1a9c0f3ba..955c240d0857 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -37,6 +37,7 @@ 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.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.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 downloadWorkerStates = new ArrayList<>(); + private String workerAccountName; + private DownloadFileOperation workerCurrentDownload; @Inject BackgroundJobManager backgroundJobManager; @Inject UserAccountManager accountManager; @@ -164,7 +165,7 @@ protected void onCreate(Bundle savedInstanceState) { recyclerView.setAdapter(userListAdapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); initializeComponentGetters(); - observeDownloadWorkerState(); + observeWorkerState(); } @@ -341,7 +342,7 @@ public void run(AccountManagerFuture future) { mUploaderBinder.cancel(accountName); } - cancelAllDownloadsForAccount(); + FileDownloadHelper.Companion.instance().cancelAllDownloadsForAccount(workerAccountName, workerCurrentDownload); } User currentUser = getUserAccountManager().getUser(); @@ -409,20 +410,6 @@ protected ServiceConnection newTransferenceServiceConnection() { return new ManageAccountsServiceConnection(); } - private void cancelAllDownloadsForAccount() { - for (DownloadWorkerState workerState : downloadWorkerStates) { - User currentUser = workerState.getUser(); - IndexedForest 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 @@ private void performAccountRemoval(User user) { 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 void onOptionItemClicked(User user, View view) { } } - private void observeDownloadWorkerState() { - DownloadWorkerStateLiveData.Companion.instance().observe(this, state -> { - Log_OC.d(TAG, "Download worker started"); - downloadWorkerStates.addAll(state); + private void observeWorkerState() { + WorkerStateLiveData.Companion.instance().observe(this, state -> { + if (state instanceof WorkerState.Download) { + Log_OC.d(TAG, "Download worker started"); + workerAccountName = ((WorkerState.Download) state).getUser().getAccountName(); + workerCurrentDownload = ((WorkerState.Download) state).getCurrentDownload(); + } }); } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt index 1c8e426f9fc6..df1e1669e88f 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt @@ -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 diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 1ceecc16f172..82413ce9076b 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -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 { diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index dcff8e8d4b14..ae8d07ec2046 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -41,7 +41,8 @@ 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 @@ private void onSynchronizeFileOperationFinish(RemoteOperationResult result) { } 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; From d69554dc3b7fae23765f9966a60a8ea811ba9d95 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 11:23:47 +0100 Subject: [PATCH 150/189] Fix tracking current download status Signed-off-by: alperozturk --- .../files/downloader/DownloadNotificationManager.kt | 4 ++++ .../client/files/downloader/FileDownloadWorker.kt | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index eddfed9f3147..176bd9ac719f 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -196,6 +196,10 @@ class DownloadNotificationManager(private val context: Context, private val view notificationManager.cancel(R.string.downloader_download_in_progress_ticker) } + fun dismissAll() { + notificationManager.cancelAll() + } + fun setCredentialContentIntent(user: User) { val intent = Intent(context, AuthenticatorActivity::class.java).apply { putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 8705a6a3b2f5..f38273488f55 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -128,11 +128,11 @@ class FileDownloadWorker( downloadFile(it) } - setIdleWorkerState() folder?.let { notifyForFolderResult(it) } + setIdleWorkerState() Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() } catch (t: Throwable) { @@ -144,9 +144,9 @@ class FileDownloadWorker( override fun onStopped() { Log_OC.e(TAG, "FilesDownloadWorker stopped") - cancelAllDownloads() - notificationManager.dismissDownloadInProgressNotification() removePendingDownload(currentDownload?.user?.accountName) + cancelAllDownloads() + notificationManager.dismissAll() setIdleWorkerState() super.onStopped() @@ -157,6 +157,8 @@ class FileDownloadWorker( } private fun setIdleWorkerState() { + pendingDownloads.all.clear() + currentDownload = null WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } @@ -219,8 +221,6 @@ class FileDownloadWorker( pendingDownloads.all.forEach { it.value.payload?.cancel() } - pendingDownloads.all.clear() - currentDownload = null } private fun setUser() { From 13c2600c5365066775d59841f0310b804f843c2e Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 11:33:23 +0100 Subject: [PATCH 151/189] Add dismissAll notification Signed-off-by: alperozturk --- .../client/files/downloader/DownloadNotificationManager.kt | 6 +++++- .../nextcloud/client/files/downloader/FileDownloadWorker.kt | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 176bd9ac719f..83917d883a37 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -28,6 +28,8 @@ import android.content.Context import android.content.Intent import android.graphics.BitmapFactory import android.os.Build +import android.os.Handler +import android.os.Looper import androidx.core.app.NotificationCompat import com.nextcloud.client.account.User import com.owncloud.android.R @@ -197,7 +199,9 @@ class DownloadNotificationManager(private val context: Context, private val view } fun dismissAll() { - notificationManager.cancelAll() + Handler(Looper.getMainLooper()).postDelayed({ + notificationManager.cancelAll() + }, 2000) } fun setCredentialContentIntent(user: User) { diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index f38273488f55..297d465c2bab 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -123,7 +123,6 @@ class FileDownloadWorker( notificationManager.init() addAccountUpdateListener() - setWorkerState(user) requestDownloads.forEach { downloadFile(it) } @@ -284,6 +283,7 @@ class FileDownloadWorker( return } + setWorkerState(user) Log_OC.e(TAG, "FilesDownloadWorker downloading: $downloadKey") val isAccountExist = accountManager.exists(currentDownload?.user?.toPlatformAccount()) From a8b5754ec77372747e18b0a91eb3dc2104b0bd86 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 12:08:59 +0100 Subject: [PATCH 152/189] Fix code analytics Signed-off-by: alperozturk --- .../downloader/DownloadNotificationManager.kt | 2 ++ .../files/downloader/FileDownloadWorker.kt | 20 +++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 83917d883a37..720e58072525 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -44,6 +44,7 @@ import com.owncloud.android.utils.theme.ViewThemeUtils import java.io.File import java.security.SecureRandom +@Suppress("TooManyFunctions") class DownloadNotificationManager(private val context: Context, private val viewThemeUtils: ViewThemeUtils) { private var notification: Notification? = null @@ -198,6 +199,7 @@ class DownloadNotificationManager(private val context: Context, private val view notificationManager.cancel(R.string.downloader_download_in_progress_ticker) } + @Suppress("MagicNumber") fun dismissAll() { Handler(Looper.getMainLooper()).postDelayed({ notificationManager.cancelAll() diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 297d465c2bab..5f2843ece44e 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -161,6 +161,16 @@ class FileDownloadWorker( WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } + private fun cancelAllDownloads() { + pendingDownloads.all.forEach { + it.value.payload?.cancel() + } + } + + private fun removePendingDownload(accountName: String?) { + pendingDownloads.remove(accountName) + } + private fun notifyForFolderResult(folder: OCFile) { notificationManager.notifyForResult(null, null, folder, isAnyOperationFailed) } @@ -212,16 +222,6 @@ class FileDownloadWorker( } } - private fun removePendingDownload(accountName: String?) { - pendingDownloads.remove(accountName) - } - - private fun cancelAllDownloads() { - pendingDownloads.all.forEach { - it.value.payload?.cancel() - } - } - private fun setUser() { val accountName = inputData.keyValueMap[USER_NAME] as String user = accountManager.getUser(accountName).get() From a043144572c06ab3c8d4bc1b076def6f733337a8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 12:19:12 +0100 Subject: [PATCH 153/189] Use same worker for file download Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadHelper.kt | 6 ++---- .../nextcloud/client/jobs/BackgroundJobManagerImpl.kt | 9 +++++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index e599755727ef..438419128556 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -60,10 +60,8 @@ class FileDownloadHelper { return false } - return backgroundJobManager.isStartFileDownloadJobScheduled( - user, - file - ) || FileDownloadWorker.isDownloading(user, file) + return FileDownloadWorker.isDownloading(user, file) || + (file.isFolder && backgroundJobManager.isStartFileDownloadJobScheduled(user, file)) } fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 8b4c2ef6ff48..26945772298f 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -86,6 +86,7 @@ internal class BackgroundJobManagerImpl( const val JOB_NOTIFICATION = "notification" const val JOB_ACCOUNT_REMOVAL = "account_removal" const val JOB_FILES_UPLOAD = "files_upload" + const val JOB_FOLDER_DOWNLOAD = "folder_download" const val JOB_FILES_DOWNLOAD = "files_download" const val JOB_PDF_GENERATION = "pdf_generation" const val JOB_IMMEDIATE_CALENDAR_BACKUP = "immediate_calendar_backup" @@ -509,7 +510,11 @@ internal class BackgroundJobManagerImpl( } private fun startFileDownloadJobTag(user: User, ocFile: OCFile): String { - return JOB_FILES_DOWNLOAD + user.accountName + ocFile.fileId + return if (ocFile.isFolder) { + JOB_FOLDER_DOWNLOAD + user.accountName + ocFile.fileId + } else { + JOB_FILES_DOWNLOAD + user.accountName + } } override fun isStartFileDownloadJobScheduled(user: User, ocFile: OCFile): Boolean { @@ -561,7 +566,7 @@ internal class BackgroundJobManagerImpl( .setInputData(data) .build() - workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) + workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.KEEP, request) } override fun getFileUploads(user: User): LiveData> { From 8db5767c99c701bbb8aa32a508ddb7c4c99cbf9f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 14:23:27 +0100 Subject: [PATCH 154/189] Fix back to back download Signed-off-by: alperozturk --- .../java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 26945772298f..8149b24ed089 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -566,7 +566,7 @@ internal class BackgroundJobManagerImpl( .setInputData(data) .build() - workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.KEEP, request) + workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.APPEND, request) } override fun getFileUploads(user: User): LiveData> { From d3f5705969f3bf9a41d716f3bce379d2dd08b838 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 14:55:12 +0100 Subject: [PATCH 155/189] Rename argument name Signed-off-by: alperozturk --- .../files/downloader/FileDownloadIntents.kt | 4 +- .../files/downloader/FileDownloadWorker.kt | 50 ++++++++++--------- .../client/jobs/BackgroundJobManagerImpl.kt | 10 ++-- .../android/services/SyncFolderHandler.java | 4 +- .../ui/activity/FileDisplayActivity.java | 2 +- .../ui/preview/PreviewImageActivity.java | 2 +- 6 files changed, 37 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt index 9725bbd69dda..2407018ca603 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt @@ -39,7 +39,7 @@ class FileDownloadIntents(private val context: Context) { linkedToRemotePath: String ): Intent { return Intent(FileDownloadWorker.getDownloadAddedMessage()).apply { - putExtra(FileDownloadWorker.ACCOUNT_NAME, download.user.accountName) + putExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME, download.user.accountName) putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) putExtra(FileDownloadWorker.EXTRA_LINKED_TO_PATH, linkedToRemotePath) setPackage(context.packageName) @@ -53,7 +53,7 @@ class FileDownloadIntents(private val context: Context) { ): Intent { return Intent(FileDownloadWorker.getDownloadFinishMessage()).apply { putExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess) - putExtra(FileDownloadWorker.ACCOUNT_NAME, download.user.accountName) + putExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME, download.user.accountName) putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, download.remotePath) putExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR, download.behaviour) putExtra(SendShareDialog.ACTIVITY_NAME, download.activityName) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 5f2843ece44e..e1f6d6705e27 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -42,7 +42,6 @@ import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.files.services.IndexedForest import com.owncloud.android.lib.common.OwnCloudAccount -import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.OwnCloudClientManagerFactory import com.owncloud.android.lib.common.network.OnDatatransferProgressListener import com.owncloud.android.lib.common.operations.RemoteOperationResult @@ -71,21 +70,20 @@ class FileDownloadWorker( private var currentDownload: DownloadFileOperation? = null const val FILES_SEPARATOR = "," - const val FOLDER_PATH = "FOLDER_PATH" - const val USER_NAME = "USER" - const val FILE_PATH = "FILE_PATH" - const val FILES_PATH = "FILES_PATH" + const val FOLDER_REMOTE_PATH = "FOLDER_REMOTE_PATH" + const val FILE_REMOTE_PATH = "FILE_REMOTE_PATH" + const val FILES_REMOTE_PATH = "FILES_REMOTE_PATH" + const val ACCOUNT_NAME = "ACCOUNT_NAME" const val BEHAVIOUR = "BEHAVIOUR" const val DOWNLOAD_TYPE = "DOWNLOAD_TYPE" const val ACTIVITY_NAME = "ACTIVITY_NAME" const val PACKAGE_NAME = "PACKAGE_NAME" const val CONFLICT_UPLOAD_ID = "CONFLICT_UPLOAD_ID" - const val EXTRA_USER = "USER" - const val EXTRA_FILE = "FILE" - const val EXTRA_DOWNLOAD_RESULT = "RESULT" - const val EXTRA_REMOTE_PATH = "REMOTE_PATH" - const val EXTRA_LINKED_TO_PATH = "LINKED_TO" - const val ACCOUNT_NAME = "ACCOUNT_NAME" + + const val EXTRA_DOWNLOAD_RESULT = "EXTRA_DOWNLOAD_RESULT" + const val EXTRA_REMOTE_PATH = "EXTRA_REMOTE_PATH" + const val EXTRA_LINKED_TO_PATH = "EXTRA_LINKED_TO_PATH" + const val EXTRA_ACCOUNT_NAME = "EXTRA_ACCOUNT_NAME" fun isDownloading(user: User, file: OCFile): Boolean { return currentDownload?.file?.fileId == file.fileId && @@ -102,16 +100,20 @@ class FileDownloadWorker( } private val pendingDownloads = IndexedForest() + private var conflictUploadId: Long? = null private var lastPercent = 0 + private val intents = FileDownloadIntents(context) private val notificationManager = DownloadNotificationManager(context, viewThemeUtils) private var downloadProgressListener = FileDownloadProgressListener() + + private var user: User? = null private var currentUser = Optional.empty() - private var storageManager: FileDataStorageManager? = null + + private var currentUserFileStorageManager: FileDataStorageManager? = null private var fileDataStorageManager: FileDataStorageManager? = null - private var downloadClient: OwnCloudClient? = null - private var user: User? = null + private var folder: OCFile? = null private var isAnyOperationFailed = true @@ -223,22 +225,22 @@ class FileDownloadWorker( } private fun setUser() { - val accountName = inputData.keyValueMap[USER_NAME] as String + val accountName = inputData.keyValueMap[ACCOUNT_NAME] as String user = accountManager.getUser(accountName).get() fileDataStorageManager = FileDataStorageManager(user, context.contentResolver) } private fun setFolder() { - val folderPath = inputData.keyValueMap[FOLDER_PATH] as? String? + val folderPath = inputData.keyValueMap[FOLDER_REMOTE_PATH] as? String? if (folderPath != null) { - folder = storageManager?.getFileByEncryptedRemotePath(folderPath) + folder = currentUserFileStorageManager?.getFileByEncryptedRemotePath(folderPath) } } private fun getFiles(): List { val result = arrayListOf() - val filesPath = inputData.keyValueMap[FILES_PATH] as String? + val filesPath = inputData.keyValueMap[FILES_REMOTE_PATH] as String? val filesPathList = filesPath?.split(FILES_SEPARATOR) if (filesPathList != null) { @@ -248,7 +250,7 @@ class FileDownloadWorker( } } } else { - val remotePath = inputData.keyValueMap[FILE_PATH] as String + val remotePath = inputData.keyValueMap[FILE_REMOTE_PATH] as String fileDataStorageManager?.getFileByEncryptedRemotePath(remotePath)?.let { file -> result.add(file) } @@ -296,13 +298,13 @@ class FileDownloadWorker( var downloadResult: RemoteOperationResult<*>? = null try { val ocAccount = getOCAccountForDownload() - downloadClient = + val downloadClient = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, context) downloadResult = currentDownload?.execute(downloadClient) if (downloadResult?.isSuccess == true && currentDownload?.downloadType === DownloadType.DOWNLOAD) { getCurrentFile()?.let { - FileDownloadHelper.instance().saveFile(it, currentDownload, storageManager) + FileDownloadHelper.instance().saveFile(it, currentDownload, currentUserFileStorageManager) } } } catch (e: Exception) { @@ -328,16 +330,16 @@ class FileDownloadWorker( val currentDownloadUser = accountManager.getUser(currentDownloadAccount?.name) if (currentUser != currentDownloadUser) { currentUser = currentDownloadUser - storageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) + currentUserFileStorageManager = FileDataStorageManager(currentUser.get(), context.contentResolver) } return currentDownloadUser.get().toOwnCloudAccount() } private fun getCurrentFile(): OCFile? { - var file: OCFile? = currentDownload?.file?.fileId?.let { storageManager?.getFileById(it) } + var file: OCFile? = currentDownload?.file?.fileId?.let { currentUserFileStorageManager?.getFileById(it) } if (file == null) { - file = storageManager?.getFileByDecryptedRemotePath(currentDownload?.file?.remotePath) + file = currentUserFileStorageManager?.getFileByDecryptedRemotePath(currentDownload?.file?.remotePath) } if (file == null) { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 8149b24ed089..9597b0160c8b 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -523,9 +523,9 @@ internal class BackgroundJobManagerImpl( override fun startFolderDownloadJob(folder: OCFile, user: User, filesPath: List) { val data = workDataOf( - FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FOLDER_PATH to folder.remotePath, - FileDownloadWorker.FILES_PATH to filesPath.joinToString(FileDownloadWorker.FILES_SEPARATOR), + FileDownloadWorker.ACCOUNT_NAME to user.accountName, + FileDownloadWorker.FOLDER_REMOTE_PATH to folder.remotePath, + FileDownloadWorker.FILES_REMOTE_PATH to filesPath.joinToString(FileDownloadWorker.FILES_SEPARATOR), FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() ) @@ -552,8 +552,8 @@ internal class BackgroundJobManagerImpl( val tag = startFileDownloadJobTag(user, file) val data = workDataOf( - FileDownloadWorker.USER_NAME to user.accountName, - FileDownloadWorker.FILE_PATH to file.remotePath, + FileDownloadWorker.ACCOUNT_NAME to user.accountName, + FileDownloadWorker.FILE_REMOTE_PATH to file.remotePath, FileDownloadWorker.BEHAVIOUR to behaviour, FileDownloadWorker.DOWNLOAD_TYPE to downloadType.toString(), FileDownloadWorker.ACTIVITY_NAME to activityName, diff --git a/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java b/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java index c91702076d5b..7a5d4d25f2b2 100644 --- a/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java +++ b/app/src/main/java/com/owncloud/android/services/SyncFolderHandler.java @@ -170,7 +170,7 @@ public void cancel(Account account, OCFile file){ */ private void sendBroadcastNewSyncFolder(Account account, String remotePath) { Intent added = new Intent(FileDownloadWorker.Companion.getDownloadAddedMessage()); - added.putExtra(FileDownloadWorker.ACCOUNT_NAME, account.name); + added.putExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME, account.name); added.putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, remotePath); added.setPackage(mService.getPackageName()); LocalBroadcastManager.getInstance(mService.getApplicationContext()).sendBroadcast(added); @@ -183,7 +183,7 @@ private void sendBroadcastNewSyncFolder(Account account, String remotePath) { private void sendBroadcastFinishedSyncFolder(Account account, String remotePath, boolean success) { Intent finished = new Intent(FileDownloadWorker.Companion.getDownloadFinishMessage()); - finished.putExtra(FileDownloadWorker.ACCOUNT_NAME, account.name); + finished.putExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME, account.name); finished.putExtra(FileDownloadWorker.EXTRA_REMOTE_PATH, remotePath); finished.putExtra(FileDownloadWorker.EXTRA_DOWNLOAD_RESULT, success); finished.setPackage(mService.getPackageName()); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 43d7a3a740a4..04cfc96f956c 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1472,7 +1472,7 @@ private boolean isAscendant(String linkedToRemotePath) { } private boolean isSameAccount(Intent intent) { - String accountName = intent.getStringExtra(FileDownloadWorker.ACCOUNT_NAME); + String accountName = intent.getStringExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME); return accountName != null && getAccount() != null && accountName.equals(getAccount().name); } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index ae8d07ec2046..261e1c0f8f22 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -507,7 +507,7 @@ public void onReceive(Context context, Intent intent) { } private void previewNewImage(Intent intent) { - String accountName = intent.getStringExtra(FileDownloadWorker.ACCOUNT_NAME); + String accountName = intent.getStringExtra(FileDownloadWorker.EXTRA_ACCOUNT_NAME); String downloadedRemotePath = intent.getStringExtra(FileDownloadWorker.EXTRA_REMOTE_PATH); String downloadBehaviour = intent.getStringExtra(OCFileListFragment.DOWNLOAD_BEHAVIOUR); if (getAccount().name.equals(accountName) && downloadedRemotePath != null) { From 28d17e38d2b060b411953ab131e8c584bbdc75e0 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 12:57:33 +0100 Subject: [PATCH 156/189] Rebase master Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 6 ++-- .../files/downloader/FileDownloadWorker.kt | 9 ++++-- .../operations/DownloadFileOperation.java | 32 ++++++++----------- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 438419128556..75e266a4f230 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -66,12 +66,14 @@ class FileDownloadHelper { fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return + FileDownloadWorker.cancelCurrentDownload(user, file) backgroundJobManager.cancelFilesDownloadJob(user, file) } - fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation) { - if (currentDownload.user.nameEquals(accountName)) { + fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation?) { + if (currentDownload?.user?.nameEquals(accountName) == true) { currentDownload.file?.let { file -> + FileDownloadWorker.cancelCurrentDownload(currentDownload.user, file) backgroundJobManager.cancelFilesDownloadJob(currentDownload.user, file) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index e1f6d6705e27..508a9979e875 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -86,8 +86,13 @@ class FileDownloadWorker( const val EXTRA_ACCOUNT_NAME = "EXTRA_ACCOUNT_NAME" fun isDownloading(user: User, file: OCFile): Boolean { - return currentDownload?.file?.fileId == file.fileId && - currentDownload?.user?.accountName == user.accountName + return currentDownload?.isActive(user, file) ?: false + } + + fun cancelCurrentDownload(user: User, file: OCFile) { + if (currentDownload?.isActive(user, file) == true) { + currentDownload?.cancel() + } } fun getDownloadAddedMessage(): String { diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index 65e89fece9cd..d00ab8b6a12b 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -43,7 +43,6 @@ import java.io.File; import java.io.FileOutputStream; -import java.lang.ref.WeakReference; import java.util.HashSet; import java.util.Iterator; import java.util.Set; @@ -63,7 +62,7 @@ public class DownloadFileOperation extends RemoteOperation { private String packageName; private DownloadType downloadType; - private final WeakReference context; + private Context context; private Set dataTransferListeners = new HashSet<>(); private long modificationTimestamp; private DownloadFileRemoteOperation downloadOperation; @@ -91,7 +90,7 @@ public DownloadFileOperation(User user, this.behaviour = behaviour; this.activityName = activityName; this.packageName = packageName; - this.context = new WeakReference<>(context); + this.context = context; this.downloadType = downloadType; } @@ -99,10 +98,13 @@ public DownloadFileOperation(User user, OCFile file, Context context) { this(user, file, null, null, null, context, DownloadType.DOWNLOAD); } - public void cancelMatchingOperation(String accountName, long fileId) { - if (getFile().getFileId() == fileId && getUser().getAccountName().equals(accountName)) { - cancel(); + public boolean isActive(User user, OCFile file) { + if (user == null || file == null) { + return false; } + + return getFile().getFileId() == file.getFileId() && + getUser().getAccountName().equals(user.getAccountName()); } public String getSavePath() { @@ -167,11 +169,6 @@ protected RemoteOperationResult run(OwnCloudClient client) { } } - Context operationContext = context.get(); - if (operationContext == null) { - return new RemoteOperationResult(RemoteOperationResult.ResultCode.UNKNOWN_ERROR); - } - RemoteOperationResult result; File newFile = null; boolean moved; @@ -192,8 +189,6 @@ protected RemoteOperationResult run(OwnCloudClient client) { result = downloadOperation.execute(client); - - if (result.isSuccess()) { modificationTimestamp = downloadOperation.getModificationTimestamp(); etag = downloadOperation.getEtag(); @@ -208,13 +203,13 @@ protected RemoteOperationResult run(OwnCloudClient client) { // decrypt file if (file.isEncrypted()) { - FileDataStorageManager fileDataStorageManager = new FileDataStorageManager(user, operationContext.getContentResolver()); + FileDataStorageManager fileDataStorageManager = new FileDataStorageManager(user, context.getContentResolver()); - OCFile parent = fileDataStorageManager.getFileByEncryptedRemotePath(file.getParentRemotePath()); + OCFile parent = fileDataStorageManager.getFileByPath(file.getParentRemotePath()); DecryptedFolderMetadata metadata = EncryptionUtils.downloadFolderMetadata(parent, client, - operationContext, + context, user); if (metadata == null) { @@ -232,7 +227,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { key, iv, authenticationTag, - new ArbitraryDataProviderImpl(operationContext), + new ArbitraryDataProviderImpl(context), user); try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile)) { @@ -252,7 +247,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { } else if (downloadType == DownloadType.EXPORT) { new FileExportUtils().exportFile(file.getFileName(), file.getMimeType(), - operationContext.getContentResolver(), + context.getContentResolver(), null, tmpFile); if (!tmpFile.delete()) { @@ -260,7 +255,6 @@ protected RemoteOperationResult run(OwnCloudClient client) { } } } - Log_OC.i(TAG, "Download of " + file.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage()); From e3664997189da5083a7be8e0ab418a8e9e0929f4 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 15:08:22 +0100 Subject: [PATCH 157/189] Fix context memory leak Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadWorker.kt | 2 -- .../android/operations/DownloadFileOperation.java | 13 +++++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 508a9979e875..178761ef8475 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -24,7 +24,6 @@ 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 @@ -66,7 +65,6 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName - @SuppressLint("StaticFieldLeak") private var currentDownload: DownloadFileOperation? = null const val FILES_SEPARATOR = "," diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index d00ab8b6a12b..1aaca764934c 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -43,6 +43,7 @@ import java.io.File; import java.io.FileOutputStream; +import java.lang.ref.WeakReference; import java.util.HashSet; import java.util.Iterator; import java.util.Set; @@ -62,7 +63,7 @@ public class DownloadFileOperation extends RemoteOperation { private String packageName; private DownloadType downloadType; - private Context context; + private final WeakReference context; private Set dataTransferListeners = new HashSet<>(); private long modificationTimestamp; private DownloadFileRemoteOperation downloadOperation; @@ -90,7 +91,7 @@ public DownloadFileOperation(User user, this.behaviour = behaviour; this.activityName = activityName; this.packageName = packageName; - this.context = context; + this.context = new WeakReference<>(context); this.downloadType = downloadType; } @@ -203,13 +204,13 @@ protected RemoteOperationResult run(OwnCloudClient client) { // decrypt file if (file.isEncrypted()) { - FileDataStorageManager fileDataStorageManager = new FileDataStorageManager(user, context.getContentResolver()); + FileDataStorageManager fileDataStorageManager = new FileDataStorageManager(user, context.get().getContentResolver()); OCFile parent = fileDataStorageManager.getFileByPath(file.getParentRemotePath()); DecryptedFolderMetadata metadata = EncryptionUtils.downloadFolderMetadata(parent, client, - context, + context.get(), user); if (metadata == null) { @@ -227,7 +228,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { key, iv, authenticationTag, - new ArbitraryDataProviderImpl(context), + new ArbitraryDataProviderImpl(context.get()), user); try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile)) { @@ -247,7 +248,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { } else if (downloadType == DownloadType.EXPORT) { new FileExportUtils().exportFile(file.getFileName(), file.getMimeType(), - context.getContentResolver(), + context.get().getContentResolver(), null, tmpFile); if (!tmpFile.delete()) { From 2664349c1614b55c6910f9c2f7e7ee8fab0f2a9e Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 5 Jan 2024 15:35:49 +0100 Subject: [PATCH 158/189] Fix potential race condition Signed-off-by: alperozturk --- .../files/downloader/FileDownloadWorker.kt | 11 ++++++++--- .../operations/DownloadFileOperation.java | 18 +++++++++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 178761ef8475..3efb81a35d7b 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -66,6 +66,7 @@ class FileDownloadWorker( private val TAG = FileDownloadWorker::class.java.simpleName private var currentDownload: DownloadFileOperation? = null + private val lock = Any() const val FILES_SEPARATOR = "," const val FOLDER_REMOTE_PATH = "FOLDER_REMOTE_PATH" @@ -84,12 +85,16 @@ class FileDownloadWorker( const val EXTRA_ACCOUNT_NAME = "EXTRA_ACCOUNT_NAME" fun isDownloading(user: User, file: OCFile): Boolean { - return currentDownload?.isActive(user, file) ?: false + synchronized(lock) { + return currentDownload?.isActive(user, file) ?: false + } } fun cancelCurrentDownload(user: User, file: OCFile) { - if (currentDownload?.isActive(user, file) == true) { - currentDownload?.cancel() + synchronized(lock) { + if (currentDownload?.isActive(user, file) == true) { + currentDownload?.cancel() + } } } diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index 1aaca764934c..e0e28af5a40d 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -170,6 +170,11 @@ protected RemoteOperationResult run(OwnCloudClient client) { } } + Context operationContext = context.get(); + if (operationContext == null) { + return new RemoteOperationResult(RemoteOperationResult.ResultCode.UNKNOWN_ERROR); + } + RemoteOperationResult result; File newFile = null; boolean moved; @@ -190,6 +195,8 @@ protected RemoteOperationResult run(OwnCloudClient client) { result = downloadOperation.execute(client); + + if (result.isSuccess()) { modificationTimestamp = downloadOperation.getModificationTimestamp(); etag = downloadOperation.getEtag(); @@ -204,13 +211,13 @@ protected RemoteOperationResult run(OwnCloudClient client) { // decrypt file if (file.isEncrypted()) { - FileDataStorageManager fileDataStorageManager = new FileDataStorageManager(user, context.get().getContentResolver()); + FileDataStorageManager fileDataStorageManager = new FileDataStorageManager(user, operationContext.getContentResolver()); - OCFile parent = fileDataStorageManager.getFileByPath(file.getParentRemotePath()); + OCFile parent = fileDataStorageManager.getFileByEncryptedRemotePath(file.getParentRemotePath()); DecryptedFolderMetadata metadata = EncryptionUtils.downloadFolderMetadata(parent, client, - context.get(), + operationContext, user); if (metadata == null) { @@ -228,7 +235,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { key, iv, authenticationTag, - new ArbitraryDataProviderImpl(context.get()), + new ArbitraryDataProviderImpl(operationContext), user); try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile)) { @@ -248,7 +255,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { } else if (downloadType == DownloadType.EXPORT) { new FileExportUtils().exportFile(file.getFileName(), file.getMimeType(), - context.get().getContentResolver(), + operationContext.getContentResolver(), null, tmpFile); if (!tmpFile.delete()) { @@ -256,6 +263,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { } } } + Log_OC.i(TAG, "Download of " + file.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage()); From 578e450c6f3f148bfc5b390a81e0810fa71e3b1b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 12:03:22 +0100 Subject: [PATCH 159/189] Unify download notifications Signed-off-by: alperozturk --- .../downloader/DownloadNotificationManager.kt | 160 ++++-------------- .../files/downloader/FileDownloadIntents.kt | 15 ++ .../files/downloader/FileDownloadWorker.kt | 85 +++++----- .../client/jobs/BackgroundJobFactory.kt | 1 - app/src/main/res/values/strings.xml | 4 + 5 files changed, 97 insertions(+), 168 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 720e58072525..d0f381c418c5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -31,30 +31,27 @@ import android.os.Build import android.os.Handler import android.os.Looper import androidx.core.app.NotificationCompat -import com.nextcloud.client.account.User import com.owncloud.android.R -import com.owncloud.android.authentication.AuthenticatorActivity -import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.resources.files.FileUtils import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.ui.notifications.NotificationUtils -import com.owncloud.android.utils.ErrorMessageAdapter import com.owncloud.android.utils.theme.ViewThemeUtils import java.io.File -import java.security.SecureRandom @Suppress("TooManyFunctions") -class DownloadNotificationManager(private val context: Context, private val viewThemeUtils: ViewThemeUtils) { - - private var notification: Notification? = null - private lateinit var notificationBuilder: NotificationCompat.Builder +class DownloadNotificationManager( + private val id: Int, + private val context: Context, + private val viewThemeUtils: ViewThemeUtils +) { + + private var notification: Notification + private var notificationBuilder: NotificationCompat.Builder private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - fun init() { + init { notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply { setContentTitle(context.resources.getString(R.string.app_name)) - setContentText(context.resources.getString(R.string.worker_download)) setSmallIcon(R.drawable.notification_icon) setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) @@ -67,11 +64,9 @@ class DownloadNotificationManager(private val context: Context, private val view } @Suppress("MagicNumber") - fun notifyForStart(operation: DownloadFileOperation) { + fun prepareForStart(operation: DownloadFileOperation) { notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply { setSmallIcon(R.drawable.notification_icon) - setTicker(context.getString(R.string.downloader_download_in_progress_ticker)) - setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) setOngoing(true) setProgress(100, 0, operation.size < 0) setContentText( @@ -84,141 +79,52 @@ class DownloadNotificationManager(private val context: Context, private val view if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD) } + + notificationManager.notify( + id, + this.build() + ) } } - fun prepareForResult( - downloadResult: RemoteOperationResult<*>, - needsToUpdateCredentials: Boolean - ) { - val tickerId = getTickerId(downloadResult.isSuccess, needsToUpdateCredentials, null, null) - + fun prepareForResult() { notificationBuilder - .setTicker(context.getString(tickerId)) - .setContentTitle(context.getString(tickerId)) .setAutoCancel(true) .setOngoing(false) .setProgress(0, 0, false) } @Suppress("MagicNumber") - fun notifyForResult( - result: RemoteOperationResult<*>?, - download: DownloadFileOperation?, - folder: OCFile?, - isAnyOperationFailed: Boolean? - ) { - dismissDownloadInProgressNotification() - - val tickerId = getTickerId(result?.isSuccess, null, folder, isAnyOperationFailed) - val notifyId = SecureRandom().nextInt() - val resultText = getResultText(result, download, folder, isAnyOperationFailed) - + fun updateDownloadProgress(filePath: String, percent: Int, totalToTransfer: Long) { notificationBuilder.run { - setTicker(context.getString(tickerId)) - setContentText(resultText) - notificationManager.notify(notifyId, this.build()) - } - - NotificationUtils.cancelWithDelay( - notificationManager, - notifyId, - 2000 - ) - } - - private fun getResultText( - result: RemoteOperationResult<*>?, - download: DownloadFileOperation?, - folder: OCFile?, - isAnyOperationFailed: Boolean? - ): String { - return folder?.let { - getFolderResultText(isAnyOperationFailed, it) - } ?: if (result?.isSuccess == true) { - download?.file?.fileName ?: "" - } else { - ErrorMessageAdapter.getErrorCauseMessage(result, download, context.resources) - } - } - - private fun getFolderResultText(isAnyOperationFailed: Boolean?, folder: OCFile): String { - return if (isAnyOperationFailed == false) { - context.getString(R.string.downloader_folder_downloaded, folder.fileName) - } else { - context.getString(R.string.downloader_folder_download_failed, folder.fileName) - } - } - - private fun getTickerId( - isSuccess: Boolean?, - needsToUpdateCredentials: Boolean?, - folder: OCFile?, - isAnyOperationFailed: Boolean? - ): Int { - return if (needsToUpdateCredentials == true) { - R.string.downloader_download_failed_credentials_error - } else { - folder?.let { getFolderTickerId(isAnyOperationFailed) } ?: getFileTickerId(isSuccess) - } - } - - private fun getFileTickerId(isSuccess: Boolean?): Int { - return if (isSuccess == true) { - R.string.downloader_download_succeeded_ticker - } else { - R.string.downloader_download_failed_ticker - } - } - - private fun getFolderTickerId(isAnyOperationFailed: Boolean?): Int { - return if (isAnyOperationFailed == false) { - R.string.downloader_folder_downloaded - } else { - R.string.downloader_folder_download_failed + setProgress(100, percent, totalToTransfer < 0) + val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) + val text = + String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) + updateNotificationText(text) } } @Suppress("MagicNumber") - fun updateDownloadProgressNotification(filePath: String, percent: Int, totalToTransfer: Long) { - notificationBuilder.setProgress(100, percent, totalToTransfer < 0) - val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) - val text = - String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) - notificationBuilder.setContentText(text) - } - - fun showDownloadInProgressNotification() { - notificationManager.notify( - R.string.downloader_download_in_progress_ticker, - notificationBuilder.build() - ) - } - - fun dismissDownloadInProgressNotification() { - notificationManager.cancel(R.string.downloader_download_in_progress_ticker) + fun showCompleteNotification(text: String) { + Handler(Looper.getMainLooper()).postDelayed({ + updateNotificationText(text) + dismissNotification() + }, 3000) } @Suppress("MagicNumber") - fun dismissAll() { + fun dismissNotification() { Handler(Looper.getMainLooper()).postDelayed({ - notificationManager.cancelAll() + notificationManager.cancel(id) }, 2000) } - fun setCredentialContentIntent(user: User) { - val intent = Intent(context, AuthenticatorActivity::class.java).apply { - putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) - putExtra( - AuthenticatorActivity.EXTRA_ACTION, - AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN - ) - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) - addFlags(Intent.FLAG_FROM_BACKGROUND) + private fun updateNotificationText(text: String) { + notificationBuilder.run { + setContentText(text) + notificationManager.notify(id, this.build()) } - - setContentIntent(intent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE) } fun setContentIntent(intent: Intent, flag: Int) { diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt index 2407018ca603..78f15a07291d 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadIntents.kt @@ -23,6 +23,8 @@ package com.nextcloud.client.files.downloader import android.content.Context import android.content.Intent +import com.nextcloud.client.account.User +import com.owncloud.android.authentication.AuthenticatorActivity import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.ui.activity.FileActivity @@ -65,6 +67,19 @@ class FileDownloadIntents(private val context: Context) { } } + fun credentialContentIntent(user: User): Intent { + return Intent(context, AuthenticatorActivity::class.java).apply { + putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, user.toPlatformAccount()) + putExtra( + AuthenticatorActivity.EXTRA_ACTION, + AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN + ) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + addFlags(Intent.FLAG_FROM_BACKGROUND) + } + } + fun detailsIntent(operation: DownloadFileOperation?): Intent { return if (operation != null) { if (PreviewImageFragment.canBePreviewed(operation.file)) { diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 3efb81a35d7b..15a0f1f1bbe4 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -36,9 +36,9 @@ import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional import com.nextcloud.model.WorkerState import com.nextcloud.model.WorkerStateLiveData +import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.files.services.IndexedForest import com.owncloud.android.lib.common.OwnCloudAccount import com.owncloud.android.lib.common.OwnCloudClientManagerFactory @@ -49,14 +49,14 @@ import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.operations.DownloadType import com.owncloud.android.utils.theme.ViewThemeUtils +import java.security.SecureRandom import java.util.AbstractList import java.util.Vector @Suppress("LongParameterList", "TooManyFunctions") class FileDownloadWorker( - viewThemeUtils: ViewThemeUtils, + private val viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, - private val uploadsStorageManager: UploadsStorageManager, private var localBroadcastManager: LocalBroadcastManager, private val context: Context, params: WorkerParameters @@ -113,7 +113,7 @@ class FileDownloadWorker( private var lastPercent = 0 private val intents = FileDownloadIntents(context) - private val notificationManager = DownloadNotificationManager(context, viewThemeUtils) + private val notificationManager = DownloadNotificationManager(SecureRandom().nextInt(), context, viewThemeUtils) private var downloadProgressListener = FileDownloadProgressListener() private var user: User? = null @@ -123,28 +123,26 @@ class FileDownloadWorker( private var fileDataStorageManager: FileDataStorageManager? = null private var folder: OCFile? = null - private var isAnyOperationFailed = true + private var failedFileNames: ArrayList = arrayListOf() @Suppress("TooGenericExceptionCaught") override fun doWork(): Result { return try { val requestDownloads = getRequestDownloads() - notificationManager.init() addAccountUpdateListener() requestDownloads.forEach { downloadFile(it) } - folder?.let { - notifyForFolderResult(it) - } + showCompleteNotification() setIdleWorkerState() Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() } catch (t: Throwable) { + notificationManager.showCompleteNotification(context.getString(R.string.downloader_unexpected_error)) Log_OC.e(TAG, "Error caught at FilesDownloadWorker(): " + t.localizedMessage) Result.failure() } @@ -155,7 +153,7 @@ class FileDownloadWorker( removePendingDownload(currentDownload?.user?.accountName) cancelAllDownloads() - notificationManager.dismissAll() + notificationManager.dismissNotification() setIdleWorkerState() super.onStopped() @@ -166,6 +164,7 @@ class FileDownloadWorker( } private fun setIdleWorkerState() { + failedFileNames.clear() pendingDownloads.all.clear() currentDownload = null WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) @@ -181,8 +180,25 @@ class FileDownloadWorker( pendingDownloads.remove(accountName) } - private fun notifyForFolderResult(folder: OCFile) { - notificationManager.notifyForResult(null, null, folder, isAnyOperationFailed) + private fun showCompleteNotification() { + val result = if (failedFileNames.isEmpty()) { + getSuccessNotificationText() + } else { + val fileNames = failedFileNames.joinToString() + context.getString(R.string.downloader_files_download_failed, fileNames) + } + + notificationManager.showCompleteNotification(result) + } + + private fun getSuccessNotificationText(): String { + return if (folder != null) { + context.getString(R.string.downloader_folder_downloaded, folder?.fileName) + } else if (currentDownload?.file != null) { + context.getString(R.string.downloader_file_downloaded, currentDownload?.file?.fileName) + } else { + context.getString(R.string.downloader_download_completed) + } } private fun getRequestDownloads(): AbstractList { @@ -241,7 +257,7 @@ class FileDownloadWorker( private fun setFolder() { val folderPath = inputData.keyValueMap[FOLDER_REMOTE_PATH] as? String? if (folderPath != null) { - folder = currentUserFileStorageManager?.getFileByEncryptedRemotePath(folderPath) + folder = fileDataStorageManager?.getFileByEncryptedRemotePath(folderPath) } } @@ -327,9 +343,8 @@ class FileDownloadWorker( lastPercent = 0 notificationManager.run { - notifyForStart(download) + prepareForStart(download) setContentIntent(intents.detailsIntent(download), PendingIntent.FLAG_IMMUTABLE) - showDownloadInProgressNotification() } } @@ -360,7 +375,7 @@ class FileDownloadWorker( private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { result?.let { - isAnyOperationFailed = !it.isSuccess + checkOperationFailures(it) } val removeResult = pendingDownloads.removePayload( @@ -383,6 +398,14 @@ class FileDownloadWorker( } } + private fun checkOperationFailures(result: RemoteOperationResult<*>) { + if (!result.isSuccess) { + currentDownload?.file?.fileName?.let { fileName -> + failedFileNames.add(fileName) + } + } + } + private fun notifyDownloadResult( download: DownloadFileOperation, downloadResult: RemoteOperationResult<*> @@ -391,38 +414,21 @@ class FileDownloadWorker( return } - // TODO Check why we calling only for success? - if (downloadResult.isSuccess) { - dismissDownloadInProgressNotification() - } - val needsToUpdateCredentials = (ResultCode.UNAUTHORIZED == downloadResult.code) notificationManager.run { - prepareForResult(downloadResult, needsToUpdateCredentials) + prepareForResult() if (needsToUpdateCredentials) { - setCredentialContentIntent(download.user) + setContentIntent( + intents.credentialContentIntent(download.user), + PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE + ) } else { setContentIntent(intents.detailsIntent(null), PendingIntent.FLAG_IMMUTABLE) } - - if (folder == null) { - notifyForResult(downloadResult, download, null, null) - } } } - private fun dismissDownloadInProgressNotification() { - // TODO Check necessity of this function call - conflictUploadId?.let { - if (it > 0) { - uploadsStorageManager.removeUpload(it) - } - } - - notificationManager.dismissDownloadInProgressNotification() - } - override fun onAccountsUpdated(accounts: Array?) { if (!accountManager.exists(currentDownload?.user?.toPlatformAccount())) { currentDownload?.cancel() @@ -440,8 +446,7 @@ class FileDownloadWorker( if (percent != lastPercent) { notificationManager.run { - updateDownloadProgressNotification(filePath, percent, totalToTransfer) - showDownloadInProgressNotification() + updateDownloadProgress(filePath, percent, totalToTransfer) } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt index 865b787d5312..e3ab4308d8b7 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt @@ -259,7 +259,6 @@ class BackgroundJobFactory @Inject constructor( return FileDownloadWorker( viewThemeUtils.get(), accountManager, - uploadsStorageManager, localBroadcastManager.get(), context, params diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2ad28653e254..a93fa464772c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -168,14 +168,18 @@ Waiting to upload %1$s (%2$d) Downloading… + Downloads are completed %1$d%% Downloading %2$s Downloaded %1$s downloaded Download failed Could not download %1$s Not downloaded yet + Error occurred while downloading %s files Error occurred while downloading %s folder %s folder successfully downloaded + %s file successfully downloaded + Unexpected error occurred while downloading files Download failed, log in again Choose account Switch account From 6bf72f4a997788c7c0a0416d66a685b858e9b44f Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 12:34:47 +0100 Subject: [PATCH 160/189] Add credentials error notification Signed-off-by: alperozturk --- .../client/files/downloader/DownloadNotificationManager.kt | 2 +- .../nextcloud/client/files/downloader/FileDownloadWorker.kt | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index d0f381c418c5..451aaf2235eb 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -120,7 +120,7 @@ class DownloadNotificationManager( }, 2000) } - private fun updateNotificationText(text: String) { + fun updateNotificationText(text: String) { notificationBuilder.run { setContentText(text) notificationManager.notify(id, this.build()) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 15a0f1f1bbe4..3b1469afc5d3 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -151,9 +151,9 @@ class FileDownloadWorker( override fun onStopped() { Log_OC.e(TAG, "FilesDownloadWorker stopped") - removePendingDownload(currentDownload?.user?.accountName) - cancelAllDownloads() notificationManager.dismissNotification() + cancelAllDownloads() + removePendingDownload(currentDownload?.user?.accountName) setIdleWorkerState() super.onStopped() @@ -419,6 +419,7 @@ class FileDownloadWorker( prepareForResult() if (needsToUpdateCredentials) { + updateNotificationText(context.getString(R.string.downloader_download_failed_credentials_error)) setContentIntent( intents.credentialContentIntent(download.user), PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE From 444e22c8c7a07c8741f1068e1418c8204a6d7b76 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 13:06:33 +0100 Subject: [PATCH 161/189] Fix sync icon for downloads in queue Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadHelper.kt | 2 +- .../client/files/downloader/FileDownloadWorker.kt | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 75e266a4f230..aa03b3b60971 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -60,7 +60,7 @@ class FileDownloadHelper { return false } - return FileDownloadWorker.isDownloading(user, file) || + return FileDownloadWorker.isFileInQueue(file) || (file.isFolder && backgroundJobManager.isStartFileDownloadJobScheduled(user, file)) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 3b1469afc5d3..6328315ecd6c 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -66,6 +66,7 @@ class FileDownloadWorker( private val TAG = FileDownloadWorker::class.java.simpleName private var currentDownload: DownloadFileOperation? = null + private var pendingDownloadFileIds: ArrayList = arrayListOf() private val lock = Any() const val FILES_SEPARATOR = "," @@ -84,10 +85,8 @@ class FileDownloadWorker( const val EXTRA_LINKED_TO_PATH = "EXTRA_LINKED_TO_PATH" const val EXTRA_ACCOUNT_NAME = "EXTRA_ACCOUNT_NAME" - fun isDownloading(user: User, file: OCFile): Boolean { - synchronized(lock) { - return currentDownload?.isActive(user, file) ?: false - } + fun isFileInQueue(file: OCFile): Boolean { + return pendingDownloadFileIds.contains(file.fileId) } fun cancelCurrentDownload(user: User, file: OCFile) { @@ -144,6 +143,7 @@ class FileDownloadWorker( } catch (t: Throwable) { notificationManager.showCompleteNotification(context.getString(R.string.downloader_unexpected_error)) Log_OC.e(TAG, "Error caught at FilesDownloadWorker(): " + t.localizedMessage) + setIdleWorkerState() Result.failure() } } @@ -166,6 +166,7 @@ class FileDownloadWorker( private fun setIdleWorkerState() { failedFileNames.clear() pendingDownloads.all.clear() + pendingDownloadFileIds.clear() currentDownload = null WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } @@ -234,6 +235,7 @@ class FileDownloadWorker( file.remotePath, operation ) + pendingDownloadFileIds.add(file.fileId) if (downloadKey != null) { requestedDownloads.add(downloadKey) @@ -382,6 +384,7 @@ class FileDownloadWorker( currentDownload?.user?.accountName, currentDownload?.remotePath ) + pendingDownloadFileIds.remove(currentDownload?.file?.fileId) val downloadResult = result ?: RemoteOperationResult(RuntimeException("Error downloading…")) From 633bc1e22ae9b793207f85c63daa148cd419f5d1 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 13:46:43 +0100 Subject: [PATCH 162/189] Add showNewNotification Signed-off-by: alperozturk --- .../downloader/DownloadNotificationManager.kt | 12 ++++++++- .../files/downloader/FileDownloadWorker.kt | 27 +++++++++---------- app/src/main/res/values/strings.xml | 3 +-- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 451aaf2235eb..11a12144167e 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -37,6 +37,7 @@ import com.owncloud.android.operations.DownloadFileOperation import com.owncloud.android.ui.notifications.NotificationUtils import com.owncloud.android.utils.theme.ViewThemeUtils import java.io.File +import java.security.SecureRandom @Suppress("TooManyFunctions") class DownloadNotificationManager( @@ -120,7 +121,16 @@ class DownloadNotificationManager( }, 2000) } - fun updateNotificationText(text: String) { + fun showNewNotification(text: String) { + val notifyId = SecureRandom().nextInt() + + notificationBuilder.run { + setContentText(text) + notificationManager.notify(notifyId, this.build()) + } + } + + private fun updateNotificationText(text: String) { notificationBuilder.run { setContentText(text) notificationManager.notify(id, this.build()) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 6328315ecd6c..2f2404dfd6f5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -122,7 +122,6 @@ class FileDownloadWorker( private var fileDataStorageManager: FileDataStorageManager? = null private var folder: OCFile? = null - private var failedFileNames: ArrayList = arrayListOf() @Suppress("TooGenericExceptionCaught") override fun doWork(): Result { @@ -164,7 +163,6 @@ class FileDownloadWorker( } private fun setIdleWorkerState() { - failedFileNames.clear() pendingDownloads.all.clear() pendingDownloadFileIds.clear() currentDownload = null @@ -181,14 +179,9 @@ class FileDownloadWorker( pendingDownloads.remove(accountName) } + @Suppress("MagicNumber") private fun showCompleteNotification() { - val result = if (failedFileNames.isEmpty()) { - getSuccessNotificationText() - } else { - val fileNames = failedFileNames.joinToString() - context.getString(R.string.downloader_files_download_failed, fileNames) - } - + val result = getSuccessNotificationText() notificationManager.showCompleteNotification(result) } @@ -377,7 +370,7 @@ class FileDownloadWorker( private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { result?.let { - checkOperationFailures(it) + showFailedDownloadNotifications(it) } val removeResult = pendingDownloads.removePayload( @@ -401,11 +394,15 @@ class FileDownloadWorker( } } - private fun checkOperationFailures(result: RemoteOperationResult<*>) { + private fun showFailedDownloadNotifications(result: RemoteOperationResult<*>) { if (!result.isSuccess) { - currentDownload?.file?.fileName?.let { fileName -> - failedFileNames.add(fileName) - } + val fileName = currentDownload?.file?.fileName ?: "" + notificationManager.showNewNotification( + context.getString( + R.string.downloader_file_download_failed, + fileName + ) + ) } } @@ -422,7 +419,7 @@ class FileDownloadWorker( prepareForResult() if (needsToUpdateCredentials) { - updateNotificationText(context.getString(R.string.downloader_download_failed_credentials_error)) + showNewNotification(context.getString(R.string.downloader_download_failed_credentials_error)) setContentIntent( intents.credentialContentIntent(download.user), PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a93fa464772c..eef79cac313d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -175,8 +175,7 @@ Download failed Could not download %1$s Not downloaded yet - Error occurred while downloading %s files - Error occurred while downloading %s folder + Error occurred while downloading %s file %s folder successfully downloaded %s file successfully downloaded Unexpected error occurred while downloading files From 5b4ce2ee1c2636b7a855285d1d1346a3aad4c57c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 13:52:24 +0100 Subject: [PATCH 163/189] Add user check for isFileInQueue Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadHelper.kt | 2 +- .../client/files/downloader/FileDownloadWorker.kt | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index aa03b3b60971..cb16c7eefc37 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -60,7 +60,7 @@ class FileDownloadHelper { return false } - return FileDownloadWorker.isFileInQueue(file) || + return FileDownloadWorker.isFileInQueue(user, file) || (file.isFolder && backgroundJobManager.isStartFileDownloadJobScheduled(user, file)) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 2f2404dfd6f5..3ffb6b65351c 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -66,7 +66,7 @@ class FileDownloadWorker( private val TAG = FileDownloadWorker::class.java.simpleName private var currentDownload: DownloadFileOperation? = null - private var pendingDownloadFileIds: ArrayList = arrayListOf() + private var pendingDownloadFileIds: ArrayList> = arrayListOf() private val lock = Any() const val FILES_SEPARATOR = "," @@ -85,8 +85,8 @@ class FileDownloadWorker( const val EXTRA_LINKED_TO_PATH = "EXTRA_LINKED_TO_PATH" const val EXTRA_ACCOUNT_NAME = "EXTRA_ACCOUNT_NAME" - fun isFileInQueue(file: OCFile): Boolean { - return pendingDownloadFileIds.contains(file.fileId) + fun isFileInQueue(user: User, file: OCFile): Boolean { + return pendingDownloadFileIds.contains(Pair(user.accountName, file.fileId)) } fun cancelCurrentDownload(user: User, file: OCFile) { @@ -228,7 +228,7 @@ class FileDownloadWorker( file.remotePath, operation ) - pendingDownloadFileIds.add(file.fileId) + pendingDownloadFileIds.add(Pair(user?.accountName, file.fileId)) if (downloadKey != null) { requestedDownloads.add(downloadKey) @@ -377,7 +377,7 @@ class FileDownloadWorker( currentDownload?.user?.accountName, currentDownload?.remotePath ) - pendingDownloadFileIds.remove(currentDownload?.file?.fileId) + pendingDownloadFileIds.remove(Pair(currentDownload?.user?.accountName, currentDownload?.file?.fileId)) val downloadResult = result ?: RemoteOperationResult(RuntimeException("Error downloading…")) From 3fe240f6d0b30c2d622570163c19769647624312 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 14:36:40 +0100 Subject: [PATCH 164/189] Fix race condition for isFileInQueue Signed-off-by: alperozturk --- .../nextcloud/client/files/downloader/FileDownloadWorker.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 3ffb6b65351c..40ee07fe3d36 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -86,7 +86,9 @@ class FileDownloadWorker( const val EXTRA_ACCOUNT_NAME = "EXTRA_ACCOUNT_NAME" fun isFileInQueue(user: User, file: OCFile): Boolean { - return pendingDownloadFileIds.contains(Pair(user.accountName, file.fileId)) + synchronized(lock) { + return pendingDownloadFileIds.contains(Pair(user.accountName, file.fileId)) + } } fun cancelCurrentDownload(user: User, file: OCFile) { From d19b1d3fb11807b0265890123ab210fd3861e8e0 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 14:45:56 +0100 Subject: [PATCH 165/189] No need for clear for each worker Signed-off-by: alperozturk --- .../com/nextcloud/client/files/downloader/FileDownloadWorker.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 40ee07fe3d36..93a95cf34816 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -166,7 +166,6 @@ class FileDownloadWorker( private fun setIdleWorkerState() { pendingDownloads.all.clear() - pendingDownloadFileIds.clear() currentDownload = null WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } From 3e4cccfc5f8ded153ad88e635fec8c32977496da Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 14:55:15 +0100 Subject: [PATCH 166/189] Cancel action remove added Signed-off-by: alperozturk --- .../com/nextcloud/client/files/downloader/FileDownloadWorker.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 93a95cf34816..d01114303bcb 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -139,6 +139,7 @@ class FileDownloadWorker( showCompleteNotification() setIdleWorkerState() + Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() } catch (t: Throwable) { @@ -173,6 +174,7 @@ class FileDownloadWorker( private fun cancelAllDownloads() { pendingDownloads.all.forEach { it.value.payload?.cancel() + pendingDownloadFileIds.remove(Pair(it.value.payload?.user?.accountName, it.value.payload?.file?.fileId)) } } From b4e541602d8c8ac5e9a69536e42ce0e19756a4d7 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 15:01:10 +0100 Subject: [PATCH 167/189] Cancel All notification when sync canncelled Signed-off-by: alperozturk --- .../client/files/downloader/DownloadNotificationManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 11a12144167e..7a9ecfb6393e 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -117,7 +117,7 @@ class DownloadNotificationManager( @Suppress("MagicNumber") fun dismissNotification() { Handler(Looper.getMainLooper()).postDelayed({ - notificationManager.cancel(id) + notificationManager.cancelAll() }, 2000) } From 51bb5893ebfbdf70e388b86545a7f228e08aeb72 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 8 Jan 2024 16:37:37 +0100 Subject: [PATCH 168/189] Fix cancel feature for individual file download inside folder Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 29 +++++-- .../files/downloader/FileDownloadWorker.kt | 78 +++++++++++++------ .../operations/DownloadFileOperation.java | 9 +-- app/src/main/res/values/strings.xml | 1 + 4 files changed, 81 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index cb16c7eefc37..6b8dcfe75f29 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -21,6 +21,8 @@ package com.nextcloud.client.files.downloader +import android.content.Intent +import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.nextcloud.client.account.User import com.nextcloud.client.jobs.BackgroundJobManager import com.owncloud.android.MainApp @@ -66,19 +68,32 @@ class FileDownloadHelper { fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return - FileDownloadWorker.cancelCurrentDownload(user, file) + + sendCancelEvent(user, file) backgroundJobManager.cancelFilesDownloadJob(user, file) } + private fun sendCancelEvent(user: User, file: OCFile) { + val intent = Intent(FileDownloadWorker.CANCEL_EVENT).apply { + putExtra(FileDownloadWorker.EVENT_ACCOUNT_NAME, user.accountName) + putExtra(FileDownloadWorker.EVENT_FILE_ID, file.fileId) + } + LocalBroadcastManager.getInstance(MainApp.getAppContext()).sendBroadcast(intent) + } + fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation?) { - if (currentDownload?.user?.nameEquals(accountName) == true) { - currentDownload.file?.let { file -> - FileDownloadWorker.cancelCurrentDownload(currentDownload.user, file) - backgroundJobManager.cancelFilesDownloadJob(currentDownload.user, file) - } + if (accountName == null || currentDownload == null) return + + val currentUser = currentDownload.user + val currentFile = currentDownload.file - currentDownload.cancel() + if (!currentUser.nameEquals(accountName)) { + return } + + currentDownload.cancel() + sendCancelEvent(currentUser, currentFile) + backgroundJobManager.cancelFilesDownloadJob(currentUser, currentFile) } fun saveFile( diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index d01114303bcb..c43225310fff 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -25,7 +25,10 @@ import android.accounts.Account import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener import android.app.PendingIntent +import android.content.BroadcastReceiver import android.content.Context +import android.content.Intent +import android.content.IntentFilter import androidx.core.util.component1 import androidx.core.util.component2 import androidx.localbroadcastmanager.content.LocalBroadcastManager @@ -55,7 +58,7 @@ import java.util.Vector @Suppress("LongParameterList", "TooManyFunctions") class FileDownloadWorker( - private val viewThemeUtils: ViewThemeUtils, + viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, private var localBroadcastManager: LocalBroadcastManager, private val context: Context, @@ -69,6 +72,10 @@ class FileDownloadWorker( private var pendingDownloadFileIds: ArrayList> = arrayListOf() private val lock = Any() + const val CANCEL_EVENT = "CANCEL_EVENT" + const val EVENT_ACCOUNT_NAME = "EVENT_ACCOUNT_NAME" + const val EVENT_FILE_ID = "EVENT_FILE_ID" + const val FILES_SEPARATOR = "," const val FOLDER_REMOTE_PATH = "FOLDER_REMOTE_PATH" const val FILE_REMOTE_PATH = "FILE_REMOTE_PATH" @@ -91,14 +98,6 @@ class FileDownloadWorker( } } - fun cancelCurrentDownload(user: User, file: OCFile) { - synchronized(lock) { - if (currentDownload?.isActive(user, file) == true) { - currentDownload?.cancel() - } - } - } - fun getDownloadAddedMessage(): String { return FileDownloadWorker::class.java.name + "DOWNLOAD_ADDED" } @@ -131,6 +130,7 @@ class FileDownloadWorker( val requestDownloads = getRequestDownloads() addAccountUpdateListener() + registerCancelEvent() requestDownloads.forEach { downloadFile(it) @@ -166,11 +166,37 @@ class FileDownloadWorker( } private fun setIdleWorkerState() { - pendingDownloads.all.clear() currentDownload = null + LocalBroadcastManager.getInstance(context).unregisterReceiver(cancelEventReceiver) WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } + private fun getEventPair(intent: Intent): Pair? { + val fileId = intent.getLongExtra(EVENT_FILE_ID, -1L) + val accountName = intent.getStringExtra(EVENT_ACCOUNT_NAME) + + return if (fileId != -1L && accountName != null) { + Pair(accountName, fileId) + } else { + null + } + } + + private fun registerCancelEvent() { + val filter = IntentFilter(CANCEL_EVENT) + LocalBroadcastManager.getInstance(context).registerReceiver(cancelEventReceiver, filter) + } + + private val cancelEventReceiver: BroadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val (accountName, fileId) = getEventPair(intent) ?: return + + pendingDownloads.all.forEach { + it.value.payload?.cancel(accountName, fileId) + } + } + } + private fun cancelAllDownloads() { pendingDownloads.all.forEach { it.value.payload?.cancel() @@ -184,18 +210,15 @@ class FileDownloadWorker( @Suppress("MagicNumber") private fun showCompleteNotification() { - val result = getSuccessNotificationText() - notificationManager.showCompleteNotification(result) - } - - private fun getSuccessNotificationText(): String { - return if (folder != null) { + val successText = if (folder != null) { context.getString(R.string.downloader_folder_downloaded, folder?.fileName) } else if (currentDownload?.file != null) { context.getString(R.string.downloader_file_downloaded, currentDownload?.file?.fileName) } else { context.getString(R.string.downloader_download_completed) } + + notificationManager.showCompleteNotification(successText) } private fun getRequestDownloads(): AbstractList { @@ -398,15 +421,24 @@ class FileDownloadWorker( } private fun showFailedDownloadNotifications(result: RemoteOperationResult<*>) { - if (!result.isSuccess) { - val fileName = currentDownload?.file?.fileName ?: "" - notificationManager.showNewNotification( - context.getString( - R.string.downloader_file_download_failed, - fileName - ) + if (result.isSuccess) { + return + } + + val fileName = currentDownload?.file?.fileName ?: "" + val failMessage = if (result.isCancelled) { + context.getString( + R.string.downloader_file_download_cancelled, + fileName + ) + } else { + context.getString( + R.string.downloader_file_download_failed, + fileName ) } + + notificationManager.showNewNotification(failMessage) } private fun notifyDownloadResult( diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index e0e28af5a40d..9bfbbd167112 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -99,13 +99,10 @@ public DownloadFileOperation(User user, OCFile file, Context context) { this(user, file, null, null, null, context, DownloadType.DOWNLOAD); } - public boolean isActive(User user, OCFile file) { - if (user == null || file == null) { - return false; + public void cancel(String accountName, long fileId) { + if (getFile().getFileId() == fileId && getUser().getAccountName().equals(accountName)) { + cancel(); } - - return getFile().getFileId() == file.getFileId() && - getUser().getAccountName().equals(user.getAccountName()); } public String getSavePath() { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eef79cac313d..ddb012e5e173 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -175,6 +175,7 @@ Download failed Could not download %1$s Not downloaded yet + %s file download cancelled Error occurred while downloading %s file %s folder successfully downloaded %s file successfully downloaded From 5ea707b003c35bb5761aa7c4944d8424735577fd Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Jan 2024 10:19:17 +0100 Subject: [PATCH 169/189] Use unique tag for all download type to fix sync problems Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 24 +++++++++---------- .../files/downloader/FileDownloadWorker.kt | 17 +++---------- .../client/jobs/BackgroundJobManager.kt | 4 ++-- .../client/jobs/BackgroundJobManagerImpl.kt | 22 +++++++---------- .../operations/DownloadFileOperation.java | 2 +- .../ui/activity/FileDisplayActivity.java | 4 ++-- 6 files changed, 29 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 6b8dcfe75f29..344c1622e804 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -62,23 +62,15 @@ class FileDownloadHelper { return false } - return FileDownloadWorker.isFileInQueue(user, file) || - (file.isFolder && backgroundJobManager.isStartFileDownloadJobScheduled(user, file)) + return backgroundJobManager.isStartFileDownloadJobScheduled(user, file.fileId) || + backgroundJobManager.isStartFileDownloadJobScheduled(user, file.parentId) } fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return sendCancelEvent(user, file) - backgroundJobManager.cancelFilesDownloadJob(user, file) - } - - private fun sendCancelEvent(user: User, file: OCFile) { - val intent = Intent(FileDownloadWorker.CANCEL_EVENT).apply { - putExtra(FileDownloadWorker.EVENT_ACCOUNT_NAME, user.accountName) - putExtra(FileDownloadWorker.EVENT_FILE_ID, file.fileId) - } - LocalBroadcastManager.getInstance(MainApp.getAppContext()).sendBroadcast(intent) + backgroundJobManager.cancelFilesDownloadJob(user, file.fileId) } fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation?) { @@ -93,7 +85,15 @@ class FileDownloadHelper { currentDownload.cancel() sendCancelEvent(currentUser, currentFile) - backgroundJobManager.cancelFilesDownloadJob(currentUser, currentFile) + backgroundJobManager.cancelFilesDownloadJob(currentUser, currentFile.fileId) + } + + private fun sendCancelEvent(user: User, file: OCFile) { + val intent = Intent(FileDownloadWorker.CANCEL_EVENT).apply { + putExtra(FileDownloadWorker.EVENT_ACCOUNT_NAME, user.accountName) + putExtra(FileDownloadWorker.EVENT_FILE_ID, file.fileId) + } + LocalBroadcastManager.getInstance(MainApp.getAppContext()).sendBroadcast(intent) } fun saveFile( diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index c43225310fff..cb0a4f70d4f3 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -68,10 +68,6 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName - private var currentDownload: DownloadFileOperation? = null - private var pendingDownloadFileIds: ArrayList> = arrayListOf() - private val lock = Any() - const val CANCEL_EVENT = "CANCEL_EVENT" const val EVENT_ACCOUNT_NAME = "EVENT_ACCOUNT_NAME" const val EVENT_FILE_ID = "EVENT_FILE_ID" @@ -92,12 +88,6 @@ class FileDownloadWorker( const val EXTRA_LINKED_TO_PATH = "EXTRA_LINKED_TO_PATH" const val EXTRA_ACCOUNT_NAME = "EXTRA_ACCOUNT_NAME" - fun isFileInQueue(user: User, file: OCFile): Boolean { - synchronized(lock) { - return pendingDownloadFileIds.contains(Pair(user.accountName, file.fileId)) - } - } - fun getDownloadAddedMessage(): String { return FileDownloadWorker::class.java.name + "DOWNLOAD_ADDED" } @@ -107,6 +97,7 @@ class FileDownloadWorker( } } + private var currentDownload: DownloadFileOperation? = null private val pendingDownloads = IndexedForest() private var conflictUploadId: Long? = null @@ -192,7 +183,7 @@ class FileDownloadWorker( val (accountName, fileId) = getEventPair(intent) ?: return pendingDownloads.all.forEach { - it.value.payload?.cancel(accountName, fileId) + it.value.payload?.cancelMatchingOperation(accountName, fileId) } } } @@ -200,7 +191,6 @@ class FileDownloadWorker( private fun cancelAllDownloads() { pendingDownloads.all.forEach { it.value.payload?.cancel() - pendingDownloadFileIds.remove(Pair(it.value.payload?.user?.accountName, it.value.payload?.file?.fileId)) } } @@ -254,7 +244,6 @@ class FileDownloadWorker( file.remotePath, operation ) - pendingDownloadFileIds.add(Pair(user?.accountName, file.fileId)) if (downloadKey != null) { requestedDownloads.add(downloadKey) @@ -290,6 +279,7 @@ class FileDownloadWorker( if (filesPathList != null) { filesPathList.forEach { + // FIXME Check if folder content not exist, DownloadFileOperation will not download via content fileDataStorageManager?.getFileByEncryptedRemotePath(it)?.let { file -> result.add(file) } @@ -403,7 +393,6 @@ class FileDownloadWorker( currentDownload?.user?.accountName, currentDownload?.remotePath ) - pendingDownloadFileIds.remove(Pair(currentDownload?.user?.accountName, currentDownload?.file?.fileId)) val downloadResult = result ?: RemoteOperationResult(RuntimeException("Error downloading…")) diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 0a37bc0585da..9fc2879be6b3 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -145,9 +145,9 @@ interface BackgroundJobManager { fun getFileUploads(user: User): LiveData> fun cancelFilesUploadJob(user: User) - fun cancelFilesDownloadJob(user: User, ocFile: OCFile) + fun cancelFilesDownloadJob(user: User, fileId: Long) - fun isStartFileDownloadJobScheduled(user: User, ocFile: OCFile): Boolean + fun isStartFileDownloadJobScheduled(user: User, fileId: Long): Boolean @Suppress("LongParameterList") fun startFileDownloadJob( diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 9597b0160c8b..948dc62eac06 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -509,16 +509,12 @@ internal class BackgroundJobManagerImpl( workManager.enqueueUniqueWork(JOB_FILES_UPLOAD + user.accountName, ExistingWorkPolicy.KEEP, request) } - private fun startFileDownloadJobTag(user: User, ocFile: OCFile): String { - return if (ocFile.isFolder) { - JOB_FOLDER_DOWNLOAD + user.accountName + ocFile.fileId - } else { - JOB_FILES_DOWNLOAD + user.accountName - } + private fun startFileDownloadJobTag(user: User, fileId: Long): String { + return JOB_FOLDER_DOWNLOAD + user.accountName + fileId } - override fun isStartFileDownloadJobScheduled(user: User, ocFile: OCFile): Boolean { - return workManager.isWorkScheduled(startFileDownloadJobTag(user, ocFile)) + override fun isStartFileDownloadJobScheduled(user: User, fileId: Long): Boolean { + return workManager.isWorkScheduled(startFileDownloadJobTag(user, fileId)) } override fun startFolderDownloadJob(folder: OCFile, user: User, filesPath: List) { @@ -529,7 +525,7 @@ internal class BackgroundJobManagerImpl( FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() ) - val tag = startFileDownloadJobTag(user, folder) + val tag = startFileDownloadJobTag(user, folder.fileId) val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) .addTag(tag) @@ -549,7 +545,7 @@ internal class BackgroundJobManagerImpl( packageName: String, conflictUploadId: Long? ) { - val tag = startFileDownloadJobTag(user, file) + val tag = startFileDownloadJobTag(user, file.fileId) val data = workDataOf( FileDownloadWorker.ACCOUNT_NAME to user.accountName, @@ -566,7 +562,7 @@ internal class BackgroundJobManagerImpl( .setInputData(data) .build() - workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.APPEND, request) + workManager.enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) } override fun getFileUploads(user: User): LiveData> { @@ -578,8 +574,8 @@ internal class BackgroundJobManagerImpl( workManager.cancelJob(JOB_FILES_UPLOAD, user) } - override fun cancelFilesDownloadJob(user: User, ocFile: OCFile) { - workManager.cancelAllWorkByTag(startFileDownloadJobTag(user, ocFile)) + override fun cancelFilesDownloadJob(user: User, fileId: Long) { + workManager.cancelAllWorkByTag(startFileDownloadJobTag(user, fileId)) } override fun startPdfGenerateAndUploadWork( diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index 9bfbbd167112..65e89fece9cd 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -99,7 +99,7 @@ public DownloadFileOperation(User user, OCFile file, Context context) { this(user, file, null, null, null, context, DownloadType.DOWNLOAD); } - public void cancel(String accountName, long fileId) { + public void cancelMatchingOperation(String accountName, long fileId) { if (getFile().getFileId() == fileId && getUser().getAccountName().equals(accountName)) { cancel(); } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 04cfc96f956c..ceb0ce1110f1 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -287,7 +287,7 @@ protected void onCreate(Bundle savedInstanceState) { checkStoragePath(); initSyncBroadcastReceiver(); - observeDownloadWorkerState(); + observeWorkerState(); } @SuppressWarnings("unchecked") @@ -1562,7 +1562,7 @@ public boolean isDrawerIndicatorAvailable() { return isRoot(getCurrentDir()); } - private void observeDownloadWorkerState() { + private void observeWorkerState() { WorkerStateLiveData.Companion.instance().observe(this, state -> { if (state instanceof WorkerState.Download) { Log_OC.d(TAG, "Download worker started"); From 1689aee89a07a10cbf3976d92663107135f4f1f4 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Jan 2024 10:29:31 +0100 Subject: [PATCH 170/189] Fix cancel for unique tag Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 1 + .../files/downloader/FileDownloadWorker.kt | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 344c1622e804..e7897ee5e032 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -69,6 +69,7 @@ class FileDownloadHelper { fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return + FileDownloadWorker.pauseWork() sendCancelEvent(user, file) backgroundJobManager.cancelFilesDownloadJob(user, file.fileId) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index cb0a4f70d4f3..bcff10469190 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -55,6 +55,7 @@ import com.owncloud.android.utils.theme.ViewThemeUtils import java.security.SecureRandom import java.util.AbstractList import java.util.Vector +import java.util.concurrent.atomic.AtomicBoolean @Suppress("LongParameterList", "TooManyFunctions") class FileDownloadWorker( @@ -68,6 +69,16 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName + private val shouldContinueExecution = AtomicBoolean(true) + + fun pauseWork() { + shouldContinueExecution.set(false) + } + + fun resumeWork() { + shouldContinueExecution.set(true) + } + const val CANCEL_EVENT = "CANCEL_EVENT" const val EVENT_ACCOUNT_NAME = "EVENT_ACCOUNT_NAME" const val EVENT_FILE_ID = "EVENT_FILE_ID" @@ -124,6 +135,10 @@ class FileDownloadWorker( registerCancelEvent() requestDownloads.forEach { + if (!shouldContinueExecution.get()) { + return@forEach + } + downloadFile(it) } @@ -185,6 +200,8 @@ class FileDownloadWorker( pendingDownloads.all.forEach { it.value.payload?.cancelMatchingOperation(accountName, fileId) } + + resumeWork() } } @@ -212,6 +229,7 @@ class FileDownloadWorker( } private fun getRequestDownloads(): AbstractList { + shouldContinueExecution.set(true) setUser() setFolder() val files = getFiles() @@ -279,7 +297,6 @@ class FileDownloadWorker( if (filesPathList != null) { filesPathList.forEach { - // FIXME Check if folder content not exist, DownloadFileOperation will not download via content fileDataStorageManager?.getFileByEncryptedRemotePath(it)?.let { file -> result.add(file) } From 8ff2914ca43259bd04d24f10dbd52e5482dee96b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Jan 2024 10:46:08 +0100 Subject: [PATCH 171/189] Rename worker observer func Signed-off-by: alperozturk --- .../com/owncloud/android/ui/preview/PreviewImageActivity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 261e1c0f8f22..52b08446117c 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -152,7 +152,7 @@ protected void onCreate(Bundle savedInstanceState) { mRequestWaitingForBinder = false; } - observeDownloadWorkerState(); + observeWorkerState(); } public void toggleActionBarVisibility(boolean hide) { @@ -306,7 +306,7 @@ private void onSynchronizeFileOperationFinish(RemoteOperationResult result) { } } - private void observeDownloadWorkerState() { + private void observeWorkerState() { WorkerStateLiveData.Companion.instance().observe(this, state -> { if (state instanceof WorkerState.Download) { Log_OC.d(TAG, "Download worker started"); From f9d330575fa075e1b131c34f2e6ca185b42ad482 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Jan 2024 10:57:12 +0100 Subject: [PATCH 172/189] Prevent unnecessary file download Signed-off-by: alperozturk --- .../java/com/owncloud/android/ui/activity/FileActivity.java | 5 ----- .../owncloud/android/ui/preview/PreviewImageActivity.java | 5 +---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index fca1cbd96bc1..151d177df8cb 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -228,15 +228,10 @@ protected void onCreate(Bundle savedInstanceState) { } } - mOperationsServiceConnection = new OperationsServiceConnection(); bindService(new Intent(this, OperationsService.class), mOperationsServiceConnection, Context.BIND_AUTO_CREATE); - if (user != null) { - FileDownloadHelper.Companion.instance().downloadFile(user, mFile); - } - mUploadServiceConnection = newTransferenceServiceConnection(); if (mUploadServiceConnection != null) { bindService(new Intent(this, FileUploader.class), mUploadServiceConnection, diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 52b08446117c..0fbf73a091a3 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -420,10 +420,7 @@ public void requestForDownload(OCFile file) { public void requestForDownload(OCFile file, String downloadBehaviour) { final User user = getUser().orElseThrow(RuntimeException::new); - - if (!FileDownloadHelper.Companion.instance().isDownloading(user, file)) { - FileDownloadHelper.Companion.instance().downloadFile(user, file, downloadBehaviour, DownloadType.DOWNLOAD, "", "", null); - } + FileDownloadHelper.Companion.instance().downloadFileIfNotStartedBefore(user, file); } /** From 7a0c5919264ceb3fb39e3a2cabb4dab1b867463a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Jan 2024 11:16:10 +0100 Subject: [PATCH 173/189] Fix cancel Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 15 +---- .../files/downloader/FileDownloadWorker.kt | 56 ++----------------- 2 files changed, 7 insertions(+), 64 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index e7897ee5e032..9984549be9da 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -21,8 +21,6 @@ package com.nextcloud.client.files.downloader -import android.content.Intent -import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.nextcloud.client.account.User import com.nextcloud.client.jobs.BackgroundJobManager import com.owncloud.android.MainApp @@ -69,8 +67,7 @@ class FileDownloadHelper { fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { if (user == null || file == null) return - FileDownloadWorker.pauseWork() - sendCancelEvent(user, file) + FileDownloadWorker.cancelOperation(user.accountName, file.fileId) backgroundJobManager.cancelFilesDownloadJob(user, file.fileId) } @@ -85,18 +82,10 @@ class FileDownloadHelper { } currentDownload.cancel() - sendCancelEvent(currentUser, currentFile) + FileDownloadWorker.cancelOperation(currentUser.accountName, currentFile.fileId) backgroundJobManager.cancelFilesDownloadJob(currentUser, currentFile.fileId) } - private fun sendCancelEvent(user: User, file: OCFile) { - val intent = Intent(FileDownloadWorker.CANCEL_EVENT).apply { - putExtra(FileDownloadWorker.EVENT_ACCOUNT_NAME, user.accountName) - putExtra(FileDownloadWorker.EVENT_FILE_ID, file.fileId) - } - LocalBroadcastManager.getInstance(MainApp.getAppContext()).sendBroadcast(intent) - } - fun saveFile( file: OCFile, currentDownload: DownloadFileOperation?, diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index bcff10469190..b11c6300604d 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -25,10 +25,7 @@ import android.accounts.Account import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener import android.app.PendingIntent -import android.content.BroadcastReceiver import android.content.Context -import android.content.Intent -import android.content.IntentFilter import androidx.core.util.component1 import androidx.core.util.component2 import androidx.localbroadcastmanager.content.LocalBroadcastManager @@ -55,7 +52,6 @@ import com.owncloud.android.utils.theme.ViewThemeUtils import java.security.SecureRandom import java.util.AbstractList import java.util.Vector -import java.util.concurrent.atomic.AtomicBoolean @Suppress("LongParameterList", "TooManyFunctions") class FileDownloadWorker( @@ -69,20 +65,14 @@ class FileDownloadWorker( companion object { private val TAG = FileDownloadWorker::class.java.simpleName - private val shouldContinueExecution = AtomicBoolean(true) + private val pendingDownloads = IndexedForest() - fun pauseWork() { - shouldContinueExecution.set(false) - } - - fun resumeWork() { - shouldContinueExecution.set(true) + fun cancelOperation(accountName: String, fileId: Long) { + pendingDownloads.all.forEach { + it.value.payload?.cancelMatchingOperation(accountName, fileId) + } } - const val CANCEL_EVENT = "CANCEL_EVENT" - const val EVENT_ACCOUNT_NAME = "EVENT_ACCOUNT_NAME" - const val EVENT_FILE_ID = "EVENT_FILE_ID" - const val FILES_SEPARATOR = "," const val FOLDER_REMOTE_PATH = "FOLDER_REMOTE_PATH" const val FILE_REMOTE_PATH = "FILE_REMOTE_PATH" @@ -109,7 +99,6 @@ class FileDownloadWorker( } private var currentDownload: DownloadFileOperation? = null - private val pendingDownloads = IndexedForest() private var conflictUploadId: Long? = null private var lastPercent = 0 @@ -132,13 +121,8 @@ class FileDownloadWorker( val requestDownloads = getRequestDownloads() addAccountUpdateListener() - registerCancelEvent() requestDownloads.forEach { - if (!shouldContinueExecution.get()) { - return@forEach - } - downloadFile(it) } @@ -173,38 +157,9 @@ class FileDownloadWorker( private fun setIdleWorkerState() { currentDownload = null - LocalBroadcastManager.getInstance(context).unregisterReceiver(cancelEventReceiver) WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } - private fun getEventPair(intent: Intent): Pair? { - val fileId = intent.getLongExtra(EVENT_FILE_ID, -1L) - val accountName = intent.getStringExtra(EVENT_ACCOUNT_NAME) - - return if (fileId != -1L && accountName != null) { - Pair(accountName, fileId) - } else { - null - } - } - - private fun registerCancelEvent() { - val filter = IntentFilter(CANCEL_EVENT) - LocalBroadcastManager.getInstance(context).registerReceiver(cancelEventReceiver, filter) - } - - private val cancelEventReceiver: BroadcastReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - val (accountName, fileId) = getEventPair(intent) ?: return - - pendingDownloads.all.forEach { - it.value.payload?.cancelMatchingOperation(accountName, fileId) - } - - resumeWork() - } - } - private fun cancelAllDownloads() { pendingDownloads.all.forEach { it.value.payload?.cancel() @@ -229,7 +184,6 @@ class FileDownloadWorker( } private fun getRequestDownloads(): AbstractList { - shouldContinueExecution.set(true) setUser() setFolder() val files = getFiles() From 5aa41ce51015bf5d4db680d0c31c6692df4e1d0a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Jan 2024 11:24:49 +0100 Subject: [PATCH 174/189] Fix cancel notification Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadWorker.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index b11c6300604d..427cdfaa744e 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -291,6 +291,8 @@ class FileDownloadWorker( return } + val fileName = currentDownload?.file?.fileName + setWorkerState(user) Log_OC.e(TAG, "FilesDownloadWorker downloading: $downloadKey") @@ -317,7 +319,7 @@ class FileDownloadWorker( Log_OC.e(TAG, "Error downloading", e) downloadResult = RemoteOperationResult(e) } finally { - cleanupDownloadProcess(downloadResult) + cleanupDownloadProcess(downloadResult, fileName) } } @@ -355,9 +357,9 @@ class FileDownloadWorker( return file } - private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { + private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?, fileName: String?) { result?.let { - showFailedDownloadNotifications(it) + showFailedDownloadNotifications(it, fileName) } val removeResult = pendingDownloads.removePayload( @@ -380,12 +382,11 @@ class FileDownloadWorker( } } - private fun showFailedDownloadNotifications(result: RemoteOperationResult<*>) { + private fun showFailedDownloadNotifications(result: RemoteOperationResult<*>, fileName: String?) { if (result.isSuccess) { return } - val fileName = currentDownload?.file?.fileName ?: "" val failMessage = if (result.isCancelled) { context.getString( R.string.downloader_file_download_cancelled, From 17cdbc23a8d8e01bcd9e2f933e4ec3c760b1e83e Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 9 Jan 2024 15:56:30 +0100 Subject: [PATCH 175/189] Fix Cancel Notification Appearance and Progress Bar Visibility Signed-off-by: alperozturk --- .../downloader/DownloadNotificationManager.kt | 13 +++++++++---- .../client/files/downloader/FileDownloadWorker.kt | 14 +++++++++++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 7a9ecfb6393e..88c50e5fb3e9 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -102,14 +102,14 @@ class DownloadNotificationManager( val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) val text = String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) - updateNotificationText(text) + updateNotificationText(text, false) } } @Suppress("MagicNumber") fun showCompleteNotification(text: String) { Handler(Looper.getMainLooper()).postDelayed({ - updateNotificationText(text) + updateNotificationText(text, true) dismissNotification() }, 3000) } @@ -117,7 +117,7 @@ class DownloadNotificationManager( @Suppress("MagicNumber") fun dismissNotification() { Handler(Looper.getMainLooper()).postDelayed({ - notificationManager.cancelAll() + notificationManager.cancel(id) }, 2000) } @@ -125,13 +125,18 @@ class DownloadNotificationManager( val notifyId = SecureRandom().nextInt() notificationBuilder.run { + setProgress(0, 0, false) setContentText(text) notificationManager.notify(notifyId, this.build()) } } - private fun updateNotificationText(text: String) { + private fun updateNotificationText(text: String, cancelProgressBar: Boolean) { notificationBuilder.run { + if (cancelProgressBar) { + setProgress(0, 0, false) + } + setContentText(text) notificationManager.notify(id, this.build()) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 427cdfaa744e..bf3c165f3df8 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -114,6 +114,7 @@ class FileDownloadWorker( private var fileDataStorageManager: FileDataStorageManager? = null private var folder: OCFile? = null + private var isAnyOperationFailed = false @Suppress("TooGenericExceptionCaught") override fun doWork(): Result { @@ -126,8 +127,7 @@ class FileDownloadWorker( downloadFile(it) } - showCompleteNotification() - + showSuccessNotification() setIdleWorkerState() Log_OC.e(TAG, "FilesDownloadWorker successfully completed") @@ -171,7 +171,12 @@ class FileDownloadWorker( } @Suppress("MagicNumber") - private fun showCompleteNotification() { + private fun showSuccessNotification() { + if (isAnyOperationFailed) { + notificationManager.dismissNotification() + return + } + val successText = if (folder != null) { context.getString(R.string.downloader_folder_downloaded, folder?.fileName) } else if (currentDownload?.file != null) { @@ -184,6 +189,7 @@ class FileDownloadWorker( } private fun getRequestDownloads(): AbstractList { + isAnyOperationFailed = false setUser() setFolder() val files = getFiles() @@ -387,6 +393,8 @@ class FileDownloadWorker( return } + isAnyOperationFailed = true + val failMessage = if (result.isCancelled) { context.getString( R.string.downloader_file_download_cancelled, From 85b68c230784570cb9aed279b3ee6d2e17b53324 Mon Sep 17 00:00:00 2001 From: Jonas Mayer Date: Tue, 9 Jan 2024 18:02:19 +0100 Subject: [PATCH 176/189] Improve Notifications Signed-off-by: Jonas Mayer --- .../files/downloader/DownloadNotificationManager.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 88c50e5fb3e9..f3c7cb0d5bc5 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -102,14 +102,16 @@ class DownloadNotificationManager( val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) val text = String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) - updateNotificationText(text, false) + val title = + context.getString(R.string.downloader_download_in_progress_ticker) + updateNotificationText(title, text, false) } } @Suppress("MagicNumber") fun showCompleteNotification(text: String) { Handler(Looper.getMainLooper()).postDelayed({ - updateNotificationText(text, true) + updateNotificationText(null,text, true) dismissNotification() }, 3000) } @@ -126,17 +128,19 @@ class DownloadNotificationManager( notificationBuilder.run { setProgress(0, 0, false) + setContentTitle(null) setContentText(text) + setOngoing(false) notificationManager.notify(notifyId, this.build()) } } - private fun updateNotificationText(text: String, cancelProgressBar: Boolean) { + private fun updateNotificationText(title: String?, text: String, cancelProgressBar: Boolean) { notificationBuilder.run { if (cancelProgressBar) { setProgress(0, 0, false) } - + setContentTitle(title) setContentText(text) notificationManager.notify(id, this.build()) } From 7970ba7b75d8974a3e191325d1600102c1a95f2a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 10:07:58 +0100 Subject: [PATCH 177/189] Add long running task support Signed-off-by: alperozturk --- app/src/main/AndroidManifest.xml | 6 ++++++ .../files/downloader/DownloadNotificationManager.kt | 10 +++++++++- .../client/files/downloader/FileDownloadWorker.kt | 10 ++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f83f59ef32fd..4fda4a48604c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -239,6 +239,12 @@ android:exported="false" android:configChanges="orientation|screenLayout|screenSize|keyboardHidden" android:theme="@style/Theme.ownCloud.Media" /> + diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index f3c7cb0d5bc5..60ce0c1911b0 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -111,7 +111,7 @@ class DownloadNotificationManager( @Suppress("MagicNumber") fun showCompleteNotification(text: String) { Handler(Looper.getMainLooper()).postDelayed({ - updateNotificationText(null,text, true) + updateNotificationText(null, text, true) dismissNotification() }, 3000) } @@ -156,4 +156,12 @@ class DownloadNotificationManager( ) ) } + + fun getId(): Int { + return id + } + + fun getNotification(): Notification { + return notificationBuilder.build() + } } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index bf3c165f3df8..b4534cfa0a63 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -36,8 +36,10 @@ import com.nextcloud.client.account.UserAccountManager import com.nextcloud.java.util.Optional import com.nextcloud.model.WorkerState import com.nextcloud.model.WorkerStateLiveData +import com.nextcloud.utils.ForegroundServiceHelper import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager +import com.owncloud.android.datamodel.ForegroundServiceType import com.owncloud.android.datamodel.OCFile import com.owncloud.android.files.services.IndexedForest import com.owncloud.android.lib.common.OwnCloudAccount @@ -123,6 +125,14 @@ class FileDownloadWorker( addAccountUpdateListener() + setForegroundAsync( + ForegroundServiceHelper.createWorkerForegroundInfo( + notificationManager.getId(), + notificationManager.getNotification(), + ForegroundServiceType.DataSync + ) + ) + requestDownloads.forEach { downloadFile(it) } From 687c5571245f4e5d4b880c86472b6d2741fa3ee9 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 10:16:26 +0100 Subject: [PATCH 178/189] Improve notifications for different custom Android OS Signed-off-by: alperozturk --- .../client/files/downloader/DownloadNotificationManager.kt | 4 ++-- app/src/main/res/values/strings.xml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 60ce0c1911b0..1683ceade7fb 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -72,7 +72,7 @@ class DownloadNotificationManager( setProgress(100, 0, operation.size < 0) setContentText( String.format( - context.getString(R.string.downloader_download_in_progress_content), 0, + context.getString(R.string.downloader_download_in_progress), 0, File(operation.savePath).name ) ) @@ -101,7 +101,7 @@ class DownloadNotificationManager( setProgress(100, percent, totalToTransfer < 0) val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1) val text = - String.format(context.getString(R.string.downloader_download_in_progress_content), percent, fileName) + String.format(context.getString(R.string.downloader_download_in_progress), percent, fileName) val title = context.getString(R.string.downloader_download_in_progress_ticker) updateNotificationText(title, text, false) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ddb012e5e173..fc427dd5516f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -169,6 +169,7 @@ %1$s (%2$d) Downloading… Downloads are completed + %1$d%% %2$s %1$d%% Downloading %2$s Downloaded %1$s downloaded From 98dd0c7210a6b7010343f6748ccedef5cbfb90b2 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 13:02:24 +0100 Subject: [PATCH 179/189] Rebase master Signed-off-by: alperozturk --- .../files/downloader/FileDownloadWorker.kt | 20 +++++++++++-------- .../client/jobs/BackgroundJobManagerImpl.kt | 2 ++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index b4534cfa0a63..29a199d7a476 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -57,7 +57,7 @@ import java.util.Vector @Suppress("LongParameterList", "TooManyFunctions") class FileDownloadWorker( - viewThemeUtils: ViewThemeUtils, + private val viewThemeUtils: ViewThemeUtils, private val accountManager: UserAccountManager, private var localBroadcastManager: LocalBroadcastManager, private val context: Context, @@ -75,6 +75,7 @@ class FileDownloadWorker( } } + const val WORKER_ID = "WORKER_ID" const val FILES_SEPARATOR = "," const val FOLDER_REMOTE_PATH = "FOLDER_REMOTE_PATH" const val FILE_REMOTE_PATH = "FILE_REMOTE_PATH" @@ -106,7 +107,7 @@ class FileDownloadWorker( private var lastPercent = 0 private val intents = FileDownloadIntents(context) - private val notificationManager = DownloadNotificationManager(SecureRandom().nextInt(), context, viewThemeUtils) + private lateinit var notificationManager: DownloadNotificationManager private var downloadProgressListener = FileDownloadProgressListener() private var user: User? = null @@ -115,6 +116,7 @@ class FileDownloadWorker( private var currentUserFileStorageManager: FileDataStorageManager? = null private var fileDataStorageManager: FileDataStorageManager? = null + private var workerId: Int? = null private var folder: OCFile? = null private var isAnyOperationFailed = false @@ -123,15 +125,16 @@ class FileDownloadWorker( return try { val requestDownloads = getRequestDownloads() + notificationManager = + DownloadNotificationManager(workerId ?: SecureRandom().nextInt(), context, viewThemeUtils) addAccountUpdateListener() - setForegroundAsync( - ForegroundServiceHelper.createWorkerForegroundInfo( - notificationManager.getId(), - notificationManager.getNotification(), - ForegroundServiceType.DataSync - ) + val foregroundInfo = ForegroundServiceHelper.createWorkerForegroundInfo( + notificationManager.getId(), + notificationManager.getNotification(), + ForegroundServiceType.DataSync ) + setForegroundAsync(foregroundInfo) requestDownloads.forEach { downloadFile(it) @@ -199,6 +202,7 @@ class FileDownloadWorker( } private fun getRequestDownloads(): AbstractList { + workerId = inputData.keyValueMap[WORKER_ID] as Int isAnyOperationFailed = false setUser() setFolder() diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index 948dc62eac06..fe667776f107 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -519,6 +519,7 @@ internal class BackgroundJobManagerImpl( override fun startFolderDownloadJob(folder: OCFile, user: User, filesPath: List) { val data = workDataOf( + FileDownloadWorker.WORKER_ID to folder.fileId.toInt(), FileDownloadWorker.ACCOUNT_NAME to user.accountName, FileDownloadWorker.FOLDER_REMOTE_PATH to folder.remotePath, FileDownloadWorker.FILES_REMOTE_PATH to filesPath.joinToString(FileDownloadWorker.FILES_SEPARATOR), @@ -548,6 +549,7 @@ internal class BackgroundJobManagerImpl( val tag = startFileDownloadJobTag(user, file.fileId) val data = workDataOf( + FileDownloadWorker.WORKER_ID to file.fileId.toInt(), FileDownloadWorker.ACCOUNT_NAME to user.accountName, FileDownloadWorker.FILE_REMOTE_PATH to file.remotePath, FileDownloadWorker.BEHAVIOUR to behaviour, From c4ba0e0b43af703a557d5f6fd3a29d3052e30f18 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 15:02:35 +0100 Subject: [PATCH 180/189] Dont show success notifications Signed-off-by: alperozturk --- .../downloader/DownloadNotificationManager.kt | 18 ++++--------- .../files/downloader/FileDownloadWorker.kt | 26 +++++-------------- app/src/main/res/values/strings.xml | 3 --- 3 files changed, 11 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 1683ceade7fb..3977928ed7b3 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -104,18 +104,10 @@ class DownloadNotificationManager( String.format(context.getString(R.string.downloader_download_in_progress), percent, fileName) val title = context.getString(R.string.downloader_download_in_progress_ticker) - updateNotificationText(title, text, false) + updateNotificationText(title, text) } } - @Suppress("MagicNumber") - fun showCompleteNotification(text: String) { - Handler(Looper.getMainLooper()).postDelayed({ - updateNotificationText(null, text, true) - dismissNotification() - }, 3000) - } - @Suppress("MagicNumber") fun dismissNotification() { Handler(Looper.getMainLooper()).postDelayed({ @@ -135,12 +127,12 @@ class DownloadNotificationManager( } } - private fun updateNotificationText(title: String?, text: String, cancelProgressBar: Boolean) { + private fun updateNotificationText(title: String?, text: String) { notificationBuilder.run { - if (cancelProgressBar) { - setProgress(0, 0, false) + title?.let { + setContentTitle(title) } - setContentTitle(title) + setContentText(text) notificationManager.notify(id, this.build()) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 29a199d7a476..da838f924961 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -140,13 +140,17 @@ class FileDownloadWorker( downloadFile(it) } - showSuccessNotification() + if (isAnyOperationFailed) { + notificationManager.dismissNotification() + } + setIdleWorkerState() Log_OC.e(TAG, "FilesDownloadWorker successfully completed") Result.success() } catch (t: Throwable) { - notificationManager.showCompleteNotification(context.getString(R.string.downloader_unexpected_error)) + notificationManager.dismissNotification() + notificationManager.showNewNotification(context.getString(R.string.downloader_unexpected_error)) Log_OC.e(TAG, "Error caught at FilesDownloadWorker(): " + t.localizedMessage) setIdleWorkerState() Result.failure() @@ -183,24 +187,6 @@ class FileDownloadWorker( pendingDownloads.remove(accountName) } - @Suppress("MagicNumber") - private fun showSuccessNotification() { - if (isAnyOperationFailed) { - notificationManager.dismissNotification() - return - } - - val successText = if (folder != null) { - context.getString(R.string.downloader_folder_downloaded, folder?.fileName) - } else if (currentDownload?.file != null) { - context.getString(R.string.downloader_file_downloaded, currentDownload?.file?.fileName) - } else { - context.getString(R.string.downloader_download_completed) - } - - notificationManager.showCompleteNotification(successText) - } - private fun getRequestDownloads(): AbstractList { workerId = inputData.keyValueMap[WORKER_ID] as Int isAnyOperationFailed = false diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fc427dd5516f..e47fe3f86174 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -168,7 +168,6 @@ Waiting to upload %1$s (%2$d) Downloading… - Downloads are completed %1$d%% %2$s %1$d%% Downloading %2$s Downloaded @@ -178,8 +177,6 @@ Not downloaded yet %s file download cancelled Error occurred while downloading %s file - %s folder successfully downloaded - %s file successfully downloaded Unexpected error occurred while downloading files Download failed, log in again Choose account From 15dedf8116a4f65c260e8f1781d2faa7bf131e91 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 16:11:49 +0100 Subject: [PATCH 181/189] Cancel fix Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 14 ++++++----- .../files/downloader/FileDownloadWorker.kt | 15 ++++++++++++ .../datamodel/FileDataStorageManager.java | 24 ++++++++++++++++++- .../operations/DownloadFileOperation.java | 6 ++++- .../ui/helpers/FileOperationsHelper.java | 3 ++- 5 files changed, 53 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 9984549be9da..e2bef7428c92 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -60,15 +60,17 @@ class FileDownloadHelper { return false } - return backgroundJobManager.isStartFileDownloadJobScheduled(user, file.fileId) || - backgroundJobManager.isStartFileDownloadJobScheduled(user, file.parentId) + return FileDownloadWorker.isDownloading(user.accountName, file.fileId) || + FileDownloadWorker.isDownloading(user.accountName, file.parentId) } - fun cancelPendingOrCurrentDownloads(user: User?, file: OCFile?) { - if (user == null || file == null) return + fun cancelPendingOrCurrentDownloads(user: User?, files: List?) { + if (user == null || files == null) return - FileDownloadWorker.cancelOperation(user.accountName, file.fileId) - backgroundJobManager.cancelFilesDownloadJob(user, file.fileId) + files.forEach { + FileDownloadWorker.cancelOperation(user.accountName, it.fileId) + backgroundJobManager.cancelFilesDownloadJob(user, it.fileId) + } } fun cancelAllDownloadsForAccount(accountName: String?, currentDownload: DownloadFileOperation?) { diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index da838f924961..f4bbaaae4a5d 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -75,6 +75,21 @@ class FileDownloadWorker( } } + /* + Folder 1 -- id = 100 + file 1-- parentID 100 + folder 2-- parentID 100 + file 3-- parentID 100 + file 4 -- parentID 100 + Folder 4 -- parentID 100 + file 6 -- parentID 100 + + */ + + fun isDownloading(accountName: String, fileId: Long): Boolean { + return pendingDownloads.all.any { it.value.payload.isMatching(accountName, fileId) } + } + const val WORKER_ID = "WORKER_ID" const val FILES_SEPARATOR = "," const val FOLDER_REMOTE_PATH = "FOLDER_REMOTE_PATH" diff --git a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index d3f1e04e2013..bd57e9a9ffef 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -180,6 +180,29 @@ public boolean fileExists(String path) { return fileDao.getFileByEncryptedRemotePath(path, user.getAccountName()) != null; } + public List getAllFilesRecursivelyInsideFolder(OCFile file) { + ArrayList result = new ArrayList<>(); + + if (file == null || !file.fileExists()) { + return result; + } + + if (!file.isFolder()) { + result.add(file); + return result; + } + + List filesInsideFolder = getFolderContent(file.getFileId(), false); + for (OCFile item: filesInsideFolder) { + if (!item.isFolder()) { + result.add(item); + } else { + result.addAll(getAllFilesRecursivelyInsideFolder(item)); + } + } + + return result; + } public List getFolderContent(OCFile ocFile, boolean onlyOnDevice) { if (ocFile != null && ocFile.isFolder() && ocFile.fileExists()) { @@ -189,7 +212,6 @@ public List getFolderContent(OCFile ocFile, boolean onlyOnDevice) { } } - public List getFolderImages(OCFile folder, boolean onlyOnDevice) { List imageList = new ArrayList<>(); diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index 65e89fece9cd..df1a62b2ab5e 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -99,8 +99,12 @@ public DownloadFileOperation(User user, OCFile file, Context context) { this(user, file, null, null, null, context, DownloadType.DOWNLOAD); } + public boolean isMatching(String accountName, long fileId) { + return getFile().getFileId() == fileId && getUser().getAccountName().equals(accountName); + } + public void cancelMatchingOperation(String accountName, long fileId) { - if (getFile().getFileId() == fileId && getUser().getAccountName().equals(accountName)) { + if (isMatching(accountName, fileId)) { cancel(); } } diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 69ee619382b2..a6c89b8c7377 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -997,7 +997,8 @@ public void cancelTransference(OCFile file) { } if (FileDownloadHelper.Companion.instance().isDownloading(currentUser, file)) { - FileDownloadHelper.Companion.instance().cancelPendingOrCurrentDownloads(currentUser, file); + List files = fileActivity.getStorageManager().getAllFilesRecursivelyInsideFolder(file); + FileDownloadHelper.Companion.instance().cancelPendingOrCurrentDownloads(currentUser, files); } FileUploaderBinder uploaderBinder = fileActivity.getFileUploaderBinder(); From eb0735e122a2138335fa39e3b0765454ce0be259 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 10 Jan 2024 17:01:06 +0100 Subject: [PATCH 182/189] Prepare all files to cancel Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadHelper.kt | 10 ++++++---- .../client/files/downloader/FileDownloadWorker.kt | 15 ++------------- .../android/operations/DownloadFileOperation.java | 1 + 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index e2bef7428c92..87b837c07ca1 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -61,15 +61,17 @@ class FileDownloadHelper { } return FileDownloadWorker.isDownloading(user.accountName, file.fileId) || - FileDownloadWorker.isDownloading(user.accountName, file.parentId) + FileDownloadWorker.isDownloading(user.accountName, file.parentId) || + backgroundJobManager.isStartFileDownloadJobScheduled(user, file.fileId) || + backgroundJobManager.isStartFileDownloadJobScheduled(user, file.parentId) } fun cancelPendingOrCurrentDownloads(user: User?, files: List?) { if (user == null || files == null) return - files.forEach { - FileDownloadWorker.cancelOperation(user.accountName, it.fileId) - backgroundJobManager.cancelFilesDownloadJob(user, it.fileId) + files.forEach { file -> + FileDownloadWorker.cancelOperation(user.accountName, file.fileId) + backgroundJobManager.cancelFilesDownloadJob(user, file.fileId) } } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index f4bbaaae4a5d..270100237bbd 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -71,23 +71,12 @@ class FileDownloadWorker( fun cancelOperation(accountName: String, fileId: Long) { pendingDownloads.all.forEach { - it.value.payload?.cancelMatchingOperation(accountName, fileId) + it.value?.payload?.cancelMatchingOperation(accountName, fileId) } } - /* - Folder 1 -- id = 100 - file 1-- parentID 100 - folder 2-- parentID 100 - file 3-- parentID 100 - file 4 -- parentID 100 - Folder 4 -- parentID 100 - file 6 -- parentID 100 - - */ - fun isDownloading(accountName: String, fileId: Long): Boolean { - return pendingDownloads.all.any { it.value.payload.isMatching(accountName, fileId) } + return pendingDownloads.all.any { it.value?.payload?.isMatching(accountName, fileId) == true } } const val WORKER_ID = "WORKER_ID" diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index df1a62b2ab5e..517aeaca197f 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -23,6 +23,7 @@ import android.content.Context; import android.text.TextUtils; +import android.util.Log; import android.webkit.MimeTypeMap; import com.nextcloud.client.account.User; From 3b2824e80e8febff9370a5b906204b51c4831472 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 11 Jan 2024 10:46:49 +0100 Subject: [PATCH 183/189] Fix recursive worker start for folder Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 5 --- .../files/downloader/FileDownloadWorker.kt | 35 ++++--------------- .../client/jobs/BackgroundJobManager.kt | 6 ---- .../client/jobs/BackgroundJobManagerImpl.kt | 20 ----------- .../SynchronizeFolderOperation.java | 33 +++-------------- 5 files changed, 11 insertions(+), 88 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 87b837c07ca1..50c6efbf41aa 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -130,11 +130,6 @@ class FileDownloadHelper { } } - fun downloadFolder(folder: OCFile, user: User, files: List) { - val filesPath = files.map { it.remotePath } - backgroundJobManager.startFolderDownloadJob(folder, user, filesPath) - } - fun downloadFile(user: User, file: OCFile) { downloadFile(user, file, downloadType = DownloadType.DOWNLOAD) } diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 270100237bbd..cad04c4c6f1c 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -80,10 +80,7 @@ class FileDownloadWorker( } const val WORKER_ID = "WORKER_ID" - const val FILES_SEPARATOR = "," - const val FOLDER_REMOTE_PATH = "FOLDER_REMOTE_PATH" const val FILE_REMOTE_PATH = "FILE_REMOTE_PATH" - const val FILES_REMOTE_PATH = "FILES_REMOTE_PATH" const val ACCOUNT_NAME = "ACCOUNT_NAME" const val BEHAVIOUR = "BEHAVIOUR" const val DOWNLOAD_TYPE = "DOWNLOAD_TYPE" @@ -121,7 +118,6 @@ class FileDownloadWorker( private var fileDataStorageManager: FileDataStorageManager? = null private var workerId: Int? = null - private var folder: OCFile? = null private var isAnyOperationFailed = false @Suppress("TooGenericExceptionCaught") @@ -193,9 +189,10 @@ class FileDownloadWorker( private fun getRequestDownloads(): AbstractList { workerId = inputData.keyValueMap[WORKER_ID] as Int + Log_OC.e(TAG, "FilesDownloadWorker started for $workerId") + isAnyOperationFailed = false setUser() - setFolder() val files = getFiles() val downloadType = getDownloadType() @@ -246,33 +243,15 @@ class FileDownloadWorker( fileDataStorageManager = FileDataStorageManager(user, context.contentResolver) } - private fun setFolder() { - val folderPath = inputData.keyValueMap[FOLDER_REMOTE_PATH] as? String? - if (folderPath != null) { - folder = fileDataStorageManager?.getFileByEncryptedRemotePath(folderPath) - } - } - private fun getFiles(): List { - val result = arrayListOf() - - val filesPath = inputData.keyValueMap[FILES_REMOTE_PATH] as String? - val filesPathList = filesPath?.split(FILES_SEPARATOR) + val remotePath = inputData.keyValueMap[FILE_REMOTE_PATH] as String? + val file = fileDataStorageManager?.getFileByEncryptedRemotePath(remotePath) ?: return listOf() - if (filesPathList != null) { - filesPathList.forEach { - fileDataStorageManager?.getFileByEncryptedRemotePath(it)?.let { file -> - result.add(file) - } - } + return if (file.isFolder) { + fileDataStorageManager?.getAllFilesRecursivelyInsideFolder(file) ?: listOf() } else { - val remotePath = inputData.keyValueMap[FILE_REMOTE_PATH] as String - fileDataStorageManager?.getFileByEncryptedRemotePath(remotePath)?.let { file -> - result.add(file) - } + listOf(file) } - - return result } private fun getDownloadType(): DownloadType? { diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt index 9fc2879be6b3..ea4c19ac5887 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt @@ -160,12 +160,6 @@ interface BackgroundJobManager { conflictUploadId: Long? ) - fun startFolderDownloadJob( - folder: OCFile, - user: User, - filesPath: List - ) - fun startPdfGenerateAndUploadWork(user: User, uploadFolder: String, imagePaths: List, pdfPath: String) fun scheduleTestJob() diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt index fe667776f107..d784f5343784 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt @@ -517,26 +517,6 @@ internal class BackgroundJobManagerImpl( return workManager.isWorkScheduled(startFileDownloadJobTag(user, fileId)) } - override fun startFolderDownloadJob(folder: OCFile, user: User, filesPath: List) { - val data = workDataOf( - FileDownloadWorker.WORKER_ID to folder.fileId.toInt(), - FileDownloadWorker.ACCOUNT_NAME to user.accountName, - FileDownloadWorker.FOLDER_REMOTE_PATH to folder.remotePath, - FileDownloadWorker.FILES_REMOTE_PATH to filesPath.joinToString(FileDownloadWorker.FILES_SEPARATOR), - FileDownloadWorker.DOWNLOAD_TYPE to DownloadType.DOWNLOAD.toString() - ) - - val tag = startFileDownloadJobTag(user, folder.fileId) - - val request = oneTimeRequestBuilder(FileDownloadWorker::class, JOB_FILES_DOWNLOAD, user) - .addTag(tag) - .setInputData(data) - .build() - - workManager - .enqueueUniqueWork(tag, ExistingWorkPolicy.REPLACE, request) - } - override fun startFileDownloadJob( user: User, file: OCFile, diff --git a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index ec65a4cc7e3b..ead21c30c95f 100644 --- a/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -376,19 +376,8 @@ private void updateLocalStateData(OCFile remoteFile, OCFile localFile, OCFile up } } - private void classifyFileForLaterSyncOrDownload(OCFile remoteFile, OCFile localFile) - throws OperationCancelledException { - if (remoteFile.isFolder()) { - /// to download children files recursively - synchronized (mCancellationRequested) { - if (mCancellationRequested.get()) { - throw new OperationCancelledException(); - } - startSyncFolderOperation(remoteFile.getRemotePath()); - } - - } else { - /// prepare content synchronization for files (any file, not just favorites) + private void classifyFileForLaterSyncOrDownload(OCFile remoteFile, OCFile localFile) { + if (!remoteFile.isFolder()) { SynchronizeFileOperation operation = new SynchronizeFileOperation( localFile, remoteFile, @@ -405,18 +394,7 @@ private void classifyFileForLaterSyncOrDownload(OCFile remoteFile, OCFile localF private void prepareOpsFromLocalKnowledge() throws OperationCancelledException { List children = getStorageManager().getFolderContent(mLocalFolder, false); for (OCFile child : children) { - /// classify file to sync/download contents later - if (child.isFolder()) { - /// to download children files recursively - synchronized(mCancellationRequested) { - if (mCancellationRequested.get()) { - throw new OperationCancelledException(); - } - startSyncFolderOperation(child.getRemotePath()); - } - - } else { - /// synchronization for regular files + if (!child.isFolder()) { if (!child.isDown()) { mFilesForDirectDownload.add(child); @@ -433,7 +411,6 @@ private void prepareOpsFromLocalKnowledge() throws OperationCancelledException { mFilesToSyncContents.add(operation); } - } } } @@ -445,9 +422,7 @@ private void syncContents() throws OperationCancelledException { private void startDirectDownloads() { - FileDownloadHelper.Companion.instance().downloadFolder(mLocalFolder, - user, - mFilesForDirectDownload); + FileDownloadHelper.Companion.instance().downloadFile(user, mLocalFolder); } /** From 2a0b754449bfe18b3ea52262ae56e14a28d7eff3 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 11 Jan 2024 10:53:58 +0100 Subject: [PATCH 184/189] Fix cancel and isDownloading Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadHelper.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 50c6efbf41aa..64e4c6319c0a 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -60,10 +60,11 @@ class FileDownloadHelper { return false } - return FileDownloadWorker.isDownloading(user.accountName, file.fileId) || - FileDownloadWorker.isDownloading(user.accountName, file.parentId) || - backgroundJobManager.isStartFileDownloadJobScheduled(user, file.fileId) || - backgroundJobManager.isStartFileDownloadJobScheduled(user, file.parentId) + return if (file.isFolder) { + backgroundJobManager.isStartFileDownloadJobScheduled(user, file.fileId) + } else { + FileDownloadWorker.isDownloading(user.accountName, file.fileId) + } } fun cancelPendingOrCurrentDownloads(user: User?, files: List?) { From 6fed74a1138cde2205543537b867f75971b610ea Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 11 Jan 2024 11:30:56 +0100 Subject: [PATCH 185/189] Fix kotlin spotless check Signed-off-by: alperozturk --- .../nextcloud/client/files/downloader/FileDownloadWorker.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index cad04c4c6f1c..41fc19f0576c 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -245,10 +245,10 @@ class FileDownloadWorker( private fun getFiles(): List { val remotePath = inputData.keyValueMap[FILE_REMOTE_PATH] as String? - val file = fileDataStorageManager?.getFileByEncryptedRemotePath(remotePath) ?: return listOf() + val file = fileDataStorageManager?.getFileByEncryptedRemotePath(remotePath) ?: return listOf() return if (file.isFolder) { - fileDataStorageManager?.getAllFilesRecursivelyInsideFolder(file) ?: listOf() + fileDataStorageManager?.getAllFilesRecursivelyInsideFolder(file) ?: listOf() } else { listOf(file) } From ed24172d12daa868ff55f7bb14bc8907e92b0601 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 11 Jan 2024 15:17:56 +0100 Subject: [PATCH 186/189] Fix isDownloading for nested folders Signed-off-by: alperozturk --- .../files/downloader/FileDownloadHelper.kt | 6 +++++- .../datamodel/FileDataStorageManager.java | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt index 64e4c6319c0a..15c30c89429f 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadHelper.kt @@ -60,8 +60,12 @@ class FileDownloadHelper { return false } + val fileStorageManager = FileDataStorageManager(user, MainApp.getAppContext().contentResolver) + val topParentId = fileStorageManager.getTopParentId(file) + return if (file.isFolder) { - backgroundJobManager.isStartFileDownloadJobScheduled(user, file.fileId) + backgroundJobManager.isStartFileDownloadJobScheduled(user, file.fileId) || + backgroundJobManager.isStartFileDownloadJobScheduled(user, topParentId) } else { FileDownloadWorker.isDownloading(user.accountName, file.fileId) } diff --git a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index bd57e9a9ffef..3d30d8aff20f 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -180,6 +180,27 @@ public boolean fileExists(String path) { return fileDao.getFileByEncryptedRemotePath(path, user.getAccountName()) != null; } + public long getTopParentId(OCFile file) { + if (file.getParentId() == 1) { + return file.getFileId(); + } + + return getTopParentIdRecursive(file); + } + + private long getTopParentIdRecursive(OCFile file) { + if (file.getParentId() == 1) { + return file.getFileId(); + } + + OCFile parentFile = getFileById(file.getParentId()); + if (parentFile != null) { + return getTopParentId(parentFile); + } + + return file.getFileId(); + } + public List getAllFilesRecursivelyInsideFolder(OCFile file) { ArrayList result = new ArrayList<>(); From 3ba4721a3683ae07410052e2400b7a0419c81908 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 11 Jan 2024 16:31:39 +0100 Subject: [PATCH 187/189] Fix cancel in same root Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadWorker.kt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 41fc19f0576c..818775643e90 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -161,8 +161,6 @@ class FileDownloadWorker( Log_OC.e(TAG, "FilesDownloadWorker stopped") notificationManager.dismissNotification() - cancelAllDownloads() - removePendingDownload(currentDownload?.user?.accountName) setIdleWorkerState() super.onStopped() @@ -173,16 +171,9 @@ class FileDownloadWorker( } private fun setIdleWorkerState() { - currentDownload = null WorkerStateLiveData.instance().setWorkState(WorkerState.Idle) } - private fun cancelAllDownloads() { - pendingDownloads.all.forEach { - it.value.payload?.cancel() - } - } - private fun removePendingDownload(accountName: String?) { pendingDownloads.remove(accountName) } From 95e9be6ce9766313a26ecd00a60f32fcfb67d281 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 11 Jan 2024 17:15:32 +0100 Subject: [PATCH 188/189] Better notifications Signed-off-by: alperozturk --- .../downloader/DownloadNotificationManager.kt | 2 +- .../files/downloader/FileDownloadError.kt | 26 +++++++++++++ .../files/downloader/FileDownloadWorker.kt | 39 ++++++++++--------- app/src/main/res/values/strings.xml | 4 +- 4 files changed, 50 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadError.kt diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt index 3977928ed7b3..c3ea0ef99710 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/DownloadNotificationManager.kt @@ -52,7 +52,7 @@ class DownloadNotificationManager( init { notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply { - setContentTitle(context.resources.getString(R.string.app_name)) + setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) setSmallIcon(R.drawable.notification_icon) setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadError.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadError.kt new file mode 100644 index 000000000000..f46783b33c47 --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadError.kt @@ -0,0 +1,26 @@ +/* + * 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 . + */ + +package com.nextcloud.client.files.downloader + +enum class FileDownloadError { + Failed, Cancelled +} diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 818775643e90..9253f849331e 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -118,7 +118,7 @@ class FileDownloadWorker( private var fileDataStorageManager: FileDataStorageManager? = null private var workerId: Int? = null - private var isAnyOperationFailed = false + private var downloadError: FileDownloadError? = null @Suppress("TooGenericExceptionCaught") override fun doWork(): Result { @@ -140,7 +140,8 @@ class FileDownloadWorker( downloadFile(it) } - if (isAnyOperationFailed) { + downloadError?.let { + showDownloadErrorNotification(it) notificationManager.dismissNotification() } @@ -182,7 +183,6 @@ class FileDownloadWorker( workerId = inputData.keyValueMap[WORKER_ID] as Int Log_OC.e(TAG, "FilesDownloadWorker started for $workerId") - isAnyOperationFailed = false setUser() val files = getFiles() val downloadType = getDownloadType() @@ -339,7 +339,7 @@ class FileDownloadWorker( private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?, fileName: String?) { result?.let { - showFailedDownloadNotifications(it, fileName) + checkDownloadError(it, fileName) } val removeResult = pendingDownloads.removePayload( @@ -362,26 +362,29 @@ class FileDownloadWorker( } } - private fun showFailedDownloadNotifications(result: RemoteOperationResult<*>, fileName: String?) { - if (result.isSuccess) { + private fun checkDownloadError(result: RemoteOperationResult<*>, fileName: String?) { + if (result.isSuccess || downloadError != null) { return } - isAnyOperationFailed = true - - val failMessage = if (result.isCancelled) { - context.getString( - R.string.downloader_file_download_cancelled, - fileName - ) + downloadError = if (result.isCancelled) { + FileDownloadError.Cancelled } else { - context.getString( - R.string.downloader_file_download_failed, - fileName - ) + FileDownloadError.Failed + } + } + + private fun showDownloadErrorNotification(downloadError: FileDownloadError) { + val text = when (downloadError) { + FileDownloadError.Cancelled -> { + context.getString(R.string.downloader_file_download_cancelled) + } + FileDownloadError.Failed -> { + context.getString(R.string.downloader_file_download_failed) + } } - notificationManager.showNewNotification(failMessage) + notificationManager.showNewNotification(text) } private fun notifyDownloadResult( diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e47fe3f86174..7f515a825cac 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -175,8 +175,8 @@ Download failed Could not download %1$s Not downloaded yet - %s file download cancelled - Error occurred while downloading %s file + Certain files were canceled during the download by user + Error occurred while downloading files Unexpected error occurred while downloading files Download failed, log in again Choose account From 909c730bde0cb965b23c3301d0e0bf555ebac3a9 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 12 Jan 2024 08:56:20 +0100 Subject: [PATCH 189/189] Remove unused parameter Signed-off-by: alperozturk --- .../client/files/downloader/FileDownloadWorker.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt index 9253f849331e..b45e50ea49cc 100644 --- a/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt +++ b/app/src/main/java/com/nextcloud/client/files/downloader/FileDownloadWorker.kt @@ -271,8 +271,6 @@ class FileDownloadWorker( return } - val fileName = currentDownload?.file?.fileName - setWorkerState(user) Log_OC.e(TAG, "FilesDownloadWorker downloading: $downloadKey") @@ -299,7 +297,7 @@ class FileDownloadWorker( Log_OC.e(TAG, "Error downloading", e) downloadResult = RemoteOperationResult(e) } finally { - cleanupDownloadProcess(downloadResult, fileName) + cleanupDownloadProcess(downloadResult) } } @@ -337,9 +335,9 @@ class FileDownloadWorker( return file } - private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?, fileName: String?) { + private fun cleanupDownloadProcess(result: RemoteOperationResult<*>?) { result?.let { - checkDownloadError(it, fileName) + checkDownloadError(it) } val removeResult = pendingDownloads.removePayload( @@ -362,7 +360,7 @@ class FileDownloadWorker( } } - private fun checkDownloadError(result: RemoteOperationResult<*>, fileName: String?) { + private fun checkDownloadError(result: RemoteOperationResult<*>) { if (result.isSuccess || downloadError != null) { return }