From 7b4ce962ec4b777f036c64b170c1f89a659a731f Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 5 May 2026 11:58:40 +0200 Subject: [PATCH 1/4] Rename .java to .kt Signed-off-by: alperozturk96 --- .../{FetchRemoteFileTask.java => FetchRemoteFileTask.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/src/main/java/com/owncloud/android/ui/asynctasks/{FetchRemoteFileTask.java => FetchRemoteFileTask.kt} (100%) diff --git a/app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.java b/app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.kt similarity index 100% rename from app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.java rename to app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.kt From 1ebfe4001373b587a72c21077c7125447883aee9 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 5 May 2026 11:58:41 +0200 Subject: [PATCH 2/4] improve remote file fetch Signed-off-by: alperozturk96 --- .../ui/activity/FileDisplayActivity.kt | 20 +- .../ui/asynctasks/FetchRemoteFileTask.kt | 201 ++++++++---------- 2 files changed, 110 insertions(+), 111 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 785a15960000..307ef447e6dd 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -169,6 +169,7 @@ import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import java.io.File +import java.lang.ref.WeakReference import java.util.function.Supplier import javax.inject.Inject @@ -3071,8 +3072,23 @@ class FileDisplayActivity : storageManager = FileDataStorageManager(user, contentResolver) } - val fetchRemoteFileTask = FetchRemoteFileTask(user, fileId, storageManager, this) - fetchRemoteFileTask.execute() + if (user == null) { + Log_OC.e(TAG, "cannot fetch remote file, user is null") + return + } + + if (capabilities.isEmpty) { + Log_OC.e(TAG, "cannot fetch remote file, capabilities is empty") + return + } + + val weakContext: WeakReference = WeakReference(this) + val task = FetchRemoteFileTask(user, fileId, storageManager, lifecycleScope, capabilities.get(), weakContext) + task.run(onComplete = { + file = it + }, showFile = { (ocFile, message) -> + showFile(ocFile, message) + }) } private fun openFileByPath(user: User, filepath: String?) { diff --git a/app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.kt b/app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.kt index c51f7d46463e..42b3ac090a8f 100644 --- a/app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.kt @@ -1,122 +1,105 @@ /* * Nextcloud - Android Client * - * SPDX-FileCopyrightText: 2019 Tobias Kaminsky - * SPDX-FileCopyrightText: 2019 Nextcloud GmbH - * SPDX-FileCopyrightText: 2025 TSI-mc - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later */ -package com.owncloud.android.ui.asynctasks; - -import android.annotation.SuppressLint; -import android.os.AsyncTask; - -import com.nextcloud.client.account.User; -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.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.lib.resources.files.ReadFileRemoteOperation; -import com.owncloud.android.lib.resources.files.SearchRemoteOperation; -import com.owncloud.android.lib.resources.files.model.RemoteFile; -import com.owncloud.android.operations.RefreshFolderOperation; -import com.owncloud.android.ui.activity.FileDisplayActivity; -import com.owncloud.android.utils.FileStorageUtils; - -import static com.owncloud.android.lib.resources.files.SearchRemoteOperation.SearchType.FILE_ID_SEARCH; - -public class FetchRemoteFileTask extends AsyncTask { - private static final String TAG = "FetchRemoteFileTask"; - private final User user; - private final String fileId; - private final FileDataStorageManager storageManager; - @SuppressLint("StaticFieldLeak") private final FileDisplayActivity fileDisplayActivity; - private OCFile ocFile; - - public FetchRemoteFileTask(User user, - String fileId, - FileDataStorageManager storageManager, - FileDisplayActivity fileDisplayActivity) { - this.user = user; - this.fileId = fileId; - this.storageManager = storageManager; - this.fileDisplayActivity = fileDisplayActivity; - } - - @Override - protected String doInBackground(Void... voids) { - final var optionalCapabilities = fileDisplayActivity.getCapabilities(); - if (optionalCapabilities.isEmpty()) { - Log_OC.e(TAG, "cannot fetch remote file capability is null"); - return ""; - } - - - SearchRemoteOperation searchRemoteOperation = new SearchRemoteOperation(fileId, - FILE_ID_SEARCH, - false, - optionalCapabilities.get()); - RemoteOperationResult remoteOperationResult = searchRemoteOperation.execute(user, fileDisplayActivity); - - if (remoteOperationResult.isSuccess() && remoteOperationResult.getData() != null) { - if (remoteOperationResult.getData().isEmpty()) { - return fileDisplayActivity.getString(R.string.remote_file_fetch_failed); - } - String remotePath = ((RemoteFile) remoteOperationResult.getData().get(0)).getRemotePath(); - - ReadFileRemoteOperation operation = new ReadFileRemoteOperation(remotePath); - RemoteOperationResult result = operation.execute(user, fileDisplayActivity); - - if (!result.isSuccess()) { - Exception exception = result.getException(); - String message = "Fetching file " + remotePath + " fails with: " + result.getLogMessage(MainApp.getAppContext()); +package com.owncloud.android.ui.asynctasks + +import android.content.Context +import com.nextcloud.client.account.User +import com.owncloud.android.R +import com.owncloud.android.datamodel.FileDataStorageManager +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation +import com.owncloud.android.lib.resources.files.SearchRemoteOperation +import com.owncloud.android.lib.resources.files.model.RemoteFile +import com.owncloud.android.lib.resources.status.OCCapability +import com.owncloud.android.operations.RefreshFolderOperation +import com.owncloud.android.utils.FileStorageUtils +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.lang.ref.WeakReference + +class FetchRemoteFileTask( + private val user: User, + private val fileId: String, + private val storageManager: FileDataStorageManager, + private val lifecycleScope: CoroutineScope, + private val capabilities: OCCapability, + private val context: WeakReference +) { + @Suppress("DEPRECATION") + fun run(onComplete: (OCFile) -> Unit, showFile: (Pair) -> Unit) { + lifecycleScope.launch(Dispatchers.IO) { + val context = context.get() ?: return@launch + var ocFile: OCFile? = null + var message: String + + val searchRemoteOperation = SearchRemoteOperation( + fileId, + SearchRemoteOperation.SearchType.FILE_ID_SEARCH, + false, + capabilities + ) + val searchResult: RemoteOperationResult<*> = searchRemoteOperation.execute(user, context) + + if (!searchResult.isSuccess || searchResult.data.isNullOrEmpty()) { + message = searchResult.getLogMessage(context) + } else { + val remotePath = (searchResult.data[0] as? RemoteFile)?.remotePath - if (exception != null) { - return exception.getMessage(); + if (remotePath == null) { + message = context.getString(R.string.remote_file_fetch_failed) } else { - return message; + val readFileResult = ReadFileRemoteOperation(remotePath).execute(user, context) + + if (!readFileResult.isSuccess) { + val exception = readFileResult.exception + message = exception?.message ?: "Fetching file $remotePath fails with: ${ + readFileResult.getLogMessage(context) + }" + } else { + val remoteFile = readFileResult.data[0] as? RemoteFile + + if (remoteFile == null) { + message = context.getString(R.string.remote_file_fetch_failed) + } else { + ocFile = FileStorageUtils.fillOCFile(remoteFile) + FileStorageUtils.searchForLocalFileInDefaultPath(ocFile, user.accountName) + ocFile = storageManager.saveFileWithParent(ocFile, context) + + val fileToSync = if (ocFile?.isFolder == true) { + ocFile + } else { + ocFile?.parentId?.let { + storageManager.getFileById(it) + } + } + RefreshFolderOperation( + fileToSync, + System.currentTimeMillis(), + true, + true, + storageManager, + user, + context + ) + .execute(user, context) + + onComplete(ocFile) + message = "" + } + } } } - RemoteFile remoteFile = (RemoteFile) result.getData().get(0); - - ocFile = FileStorageUtils.fillOCFile(remoteFile); - FileStorageUtils.searchForLocalFileInDefaultPath(ocFile, user.getAccountName()); - ocFile = storageManager.saveFileWithParent(ocFile, fileDisplayActivity); - - // also sync folder content - OCFile toSync; - if (ocFile.isFolder()) { - toSync = ocFile; - } else { - toSync = storageManager.getFileById(ocFile.getParentId()); + withContext(Dispatchers.Main) { + showFile(ocFile to message) } - - long currentSyncTime = System.currentTimeMillis(); - RemoteOperation refreshFolderOperation = new RefreshFolderOperation(toSync, - currentSyncTime, - true, - true, - storageManager, - user, - fileDisplayActivity); - refreshFolderOperation.execute(user, fileDisplayActivity); - - fileDisplayActivity.setFile(ocFile); - } else { - return remoteOperationResult.getLogMessage(MainApp.getAppContext()); } - - return ""; - } - - @Override - protected void onPostExecute(String message) { - super.onPostExecute(message); - - fileDisplayActivity.showFile(ocFile, message); } } From 2b12f25221c9083afca52b689ea7162ff02a4066 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 5 May 2026 12:27:20 +0200 Subject: [PATCH 3/4] improve remote file fetch Signed-off-by: alperozturk96 --- .../ui/activity/FileDisplayActivity.kt | 5 +- .../ui/asynctasks/FetchRemoteFileTask.kt | 149 ++++++++++-------- 2 files changed, 88 insertions(+), 66 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 307ef447e6dd..c23fc17a52bc 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -3084,9 +3084,8 @@ class FileDisplayActivity : val weakContext: WeakReference = WeakReference(this) val task = FetchRemoteFileTask(user, fileId, storageManager, lifecycleScope, capabilities.get(), weakContext) - task.run(onComplete = { - file = it - }, showFile = { (ocFile, message) -> + task.run(showFile = { (ocFile, message) -> + ocFile?.let { file = it } showFile(ocFile, message) }) } diff --git a/app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.kt b/app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.kt index 42b3ac090a8f..fcbb207f1057 100644 --- a/app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.kt @@ -4,6 +4,8 @@ * SPDX-FileCopyrightText: 2026 Alper Ozturk * SPDX-License-Identifier: AGPL-3.0-or-later */ + + package com.owncloud.android.ui.asynctasks import android.content.Context @@ -11,7 +13,7 @@ import com.nextcloud.client.account.User import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation import com.owncloud.android.lib.resources.files.SearchRemoteOperation import com.owncloud.android.lib.resources.files.model.RemoteFile @@ -24,6 +26,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.lang.ref.WeakReference +@Suppress("DEPRECATION") class FetchRemoteFileTask( private val user: User, private val fileId: String, @@ -32,74 +35,94 @@ class FetchRemoteFileTask( private val capabilities: OCCapability, private val context: WeakReference ) { - @Suppress("DEPRECATION") - fun run(onComplete: (OCFile) -> Unit, showFile: (Pair) -> Unit) { + fun run(showFile: (Pair) -> Unit) { lifecycleScope.launch(Dispatchers.IO) { - val context = context.get() ?: return@launch - var ocFile: OCFile? = null - var message: String - - val searchRemoteOperation = SearchRemoteOperation( - fileId, - SearchRemoteOperation.SearchType.FILE_ID_SEARCH, - false, - capabilities - ) - val searchResult: RemoteOperationResult<*> = searchRemoteOperation.execute(user, context) + val result = try { + Log_OC.i(TAG, "fetching remote file") + val context = context.get() ?: throw Exception("context not reachable") + fetchRemoteFile(context) + } catch (e: Exception) { + Log_OC.e(TAG, "Unexpected error during fetching remote file", e) + null to e.message + } - if (!searchResult.isSuccess || searchResult.data.isNullOrEmpty()) { - message = searchResult.getLogMessage(context) - } else { - val remotePath = (searchResult.data[0] as? RemoteFile)?.remotePath - - if (remotePath == null) { - message = context.getString(R.string.remote_file_fetch_failed) - } else { - val readFileResult = ReadFileRemoteOperation(remotePath).execute(user, context) - - if (!readFileResult.isSuccess) { - val exception = readFileResult.exception - message = exception?.message ?: "Fetching file $remotePath fails with: ${ - readFileResult.getLogMessage(context) - }" - } else { - val remoteFile = readFileResult.data[0] as? RemoteFile - - if (remoteFile == null) { - message = context.getString(R.string.remote_file_fetch_failed) - } else { - ocFile = FileStorageUtils.fillOCFile(remoteFile) - FileStorageUtils.searchForLocalFileInDefaultPath(ocFile, user.accountName) - ocFile = storageManager.saveFileWithParent(ocFile, context) - - val fileToSync = if (ocFile?.isFolder == true) { - ocFile - } else { - ocFile?.parentId?.let { - storageManager.getFileById(it) - } - } - RefreshFolderOperation( - fileToSync, - System.currentTimeMillis(), - true, - true, - storageManager, - user, - context - ) - .execute(user, context) - - onComplete(ocFile) - message = "" - } - } + withContext(Dispatchers.Main) { + if (result.first != null) { + Log_OC.i(TAG, "remote file is fetched") } + showFile(result) } + } + } - withContext(Dispatchers.Main) { - showFile(ocFile to message) + private fun fetchRemoteFile(context: Context): Pair { + val remotePath = searchRemoteFile(context) + val remoteFile = readRemoteFile(remotePath, context) + return syncAndReturnFile(remoteFile, context) to null + } + + private fun searchRemoteFile(context: Context): String { + val result = SearchRemoteOperation( + fileId, + SearchRemoteOperation.SearchType.FILE_ID_SEARCH, + false, + capabilities + ).execute(user, context) + + if (!result.isSuccess || result.data.isNullOrEmpty()) { + throw Exception("Search operation failed: ${result.getLogMessage(context)}") + } + + return (result.data[0] as? RemoteFile)?.remotePath + ?: throw Exception(context.getString(R.string.remote_file_fetch_failed)) + } + + private fun readRemoteFile(remotePath: String, context: Context): RemoteFile { + val result = ReadFileRemoteOperation(remotePath).execute(user, context) + + if (!result.isSuccess) { + throw Exception( + result.exception?.message + ?: "Fetching file $remotePath fails with: ${result.getLogMessage(context)}" + ) + } + + return (result.data[0] as? RemoteFile) + ?: throw Exception(context.getString(R.string.remote_file_fetch_failed)) + } + + private fun syncAndReturnFile(remoteFile: RemoteFile, context: Context): OCFile? { + var ocFile = FileStorageUtils.fillOCFile(remoteFile) + FileStorageUtils.searchForLocalFileInDefaultPath(ocFile, user.accountName) + ocFile = storageManager.saveFileWithParent(ocFile, context) + + val fileToSync = if (ocFile?.isFolder == true) { + ocFile + } else { + ocFile?.parentId?.let { storageManager.getFileById(it) } + } + + + if (fileToSync != null) { + val refreshFolderOperation = RefreshFolderOperation( + fileToSync, + System.currentTimeMillis(), + true, + true, + storageManager, user, context + ) + val refreshFolderOperationResult = refreshFolderOperation.execute(user, context) + if (refreshFolderOperationResult.isSuccess) { + Log_OC.i(TAG, "folder is refreshed") + } else { + Log_OC.e(TAG, "an error occurred during folder refresh") } } + + return ocFile + } + + companion object { + private const val TAG = "FetchRemoteFileTask" } } From 7786703d4c527a60cb82e2ae1afd6781b0b1d453 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 5 May 2026 12:30:46 +0200 Subject: [PATCH 4/4] improve remote file fetch Signed-off-by: alperozturk96 --- .../ui/asynctasks/FetchRemoteFileTask.kt | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.kt b/app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.kt index fcbb207f1057..8cba7f3aa3d2 100644 --- a/app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/asynctasks/FetchRemoteFileTask.kt @@ -5,7 +5,6 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - package com.owncloud.android.ui.asynctasks import android.content.Context @@ -26,7 +25,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.lang.ref.WeakReference -@Suppress("DEPRECATION") +@Suppress("DEPRECATION", "TooGenericExceptionCaught", "TooGenericExceptionThrown") class FetchRemoteFileTask( private val user: User, private val fileId: String, @@ -91,28 +90,26 @@ class FetchRemoteFileTask( ?: throw Exception(context.getString(R.string.remote_file_fetch_failed)) } - private fun syncAndReturnFile(remoteFile: RemoteFile, context: Context): OCFile? { + private fun syncAndReturnFile(remoteFile: RemoteFile, context: Context): OCFile { var ocFile = FileStorageUtils.fillOCFile(remoteFile) FileStorageUtils.searchForLocalFileInDefaultPath(ocFile, user.accountName) ocFile = storageManager.saveFileWithParent(ocFile, context) + ?: throw Exception(context.getString(R.string.remote_file_fetch_failed)) - val fileToSync = if (ocFile?.isFolder == true) { - ocFile - } else { - ocFile?.parentId?.let { storageManager.getFileById(it) } - } - + val fileToSync = if (ocFile.isFolder) ocFile else storageManager.getFileById(ocFile.parentId) if (fileToSync != null) { - val refreshFolderOperation = RefreshFolderOperation( + val result = RefreshFolderOperation( fileToSync, System.currentTimeMillis(), true, true, - storageManager, user, context + storageManager, + user, + context ) - val refreshFolderOperationResult = refreshFolderOperation.execute(user, context) - if (refreshFolderOperationResult.isSuccess) { + .execute(user, context) + if (result.isSuccess) { Log_OC.i(TAG, "folder is refreshed") } else { Log_OC.e(TAG, "an error occurred during folder refresh")