diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/LoadFilesListTask.java b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/LoadFilesListTask.java index 60e29be496..174efea721 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/LoadFilesListTask.java +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/LoadFilesListTask.java @@ -31,6 +31,7 @@ import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.concurrent.CancellationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,7 +59,6 @@ import com.amaze.filemanager.utils.DataUtils; import com.amaze.filemanager.utils.GenericExtKt; import com.amaze.filemanager.utils.OTGUtil; -import com.amaze.filemanager.utils.OnAsyncTaskFinished; import com.amaze.filemanager.utils.OnFileFound; import com.amaze.filemanager.utils.Utils; import com.amaze.trashbin.TrashBin; @@ -72,7 +72,6 @@ import android.content.pm.ResolveInfo; import android.database.Cursor; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; import android.provider.MediaStore; import android.text.format.Formatter; @@ -88,42 +87,12 @@ import jcifs.smb.SmbFile; import kotlin.collections.CollectionsKt; -public class LoadFilesListTask - extends AsyncTask>> { +public class LoadFilesListTask { private static final Logger LOG = LoggerFactory.getLogger(LoadFilesListTask.class); - private String path; - private WeakReference mainFragmentReference; - private WeakReference context; - private OpenMode openmode; - private boolean showHiddenFiles, showThumbs; - private DataUtils dataUtils = DataUtils.getInstance(); - private OnAsyncTaskFinished>> listener; - private boolean forceReload; - - public LoadFilesListTask( - Context context, - String path, - MainFragment mainFragment, - OpenMode openmode, - boolean showThumbs, - boolean showHiddenFiles, - boolean forceReload, - OnAsyncTaskFinished>> l) { - this.path = path; - this.mainFragmentReference = new WeakReference<>(mainFragment); - this.openmode = openmode; - this.context = new WeakReference<>(context); - this.showThumbs = showThumbs; - this.showHiddenFiles = showHiddenFiles; - this.listener = l; - this.forceReload = forceReload; - } + public Pair> load() throws Exception { - @Override - @SuppressWarnings({"PMD.NPathComplexity", "ComplexMethod", "LongMethod"}) - protected @Nullable Pair> doInBackground(Void... p) { final MainFragment mainFragment = this.mainFragmentReference.get(); final Context context = this.context.get(); @@ -132,19 +101,24 @@ public LoadFilesListTask( || mainFragment.getMainFragmentViewModel() == null || mainFragment.getMainActivityViewModel() == null || path == null) { - cancel(true); - return null; + + throw new CancellationException(); } HybridFile hFile = null; + MainFragmentViewModel mainFragmentViewModel = mainFragment.getMainFragmentViewModel(); + MainActivityViewModel mainActivityViewModel = mainFragment.getMainActivityViewModel(); if (OpenMode.UNKNOWN.equals(openmode) || OpenMode.CUSTOM.equals(openmode) || OpenMode.TRASH_BIN.equals(openmode)) { + hFile = new HybridFile(openmode, path); + hFile.generateMode(mainFragment.getActivity()); + openmode = hFile.getMode(); if (hFile.isSmb()) { @@ -152,69 +126,88 @@ public LoadFilesListTask( } } - if (isCancelled()) return null; - mainFragmentViewModel.setFolderCount(0); mainFragmentViewModel.setFileCount(0); + final List list; switch (openmode) { case SMB: list = listSmb(hFile, mainActivityViewModel, mainFragment); break; + case FTP: case SFTP: list = listSftp(mainActivityViewModel); break; + case CUSTOM: case TRASH_BIN: list = getCachedMediaList(mainActivityViewModel); break; + case OTG: list = listOtg(); openmode = OpenMode.OTG; break; + case DOCUMENT_FILE: list = listDocumentFiles(mainActivityViewModel); openmode = OpenMode.DOCUMENT_FILE; break; + case DROPBOX: case BOX: case GDRIVE: case ONEDRIVE: - try { - list = listCloud(mainActivityViewModel); - } catch (CloudPluginException e) { - LOG.warn("failed to load cloud files", e); - AppConfig.toast(context, context.getResources().getString(R.string.failed_no_connection)); - return new Pair<>(openmode, Collections.emptyList()); - } + list = listCloud(mainActivityViewModel); break; + case ANDROID_DATA: list = listAppDataDirectories(path); break; + default: - // we're neither in OTG not in SMB, load the list based on root/general filesystem list = listDefault(mainActivityViewModel, mainFragment); break; } if (list != null && !(openmode == OpenMode.CUSTOM - && (("5").equals(path) || ("6").equals(path) || ("7").equals(path)))) { + && ("5".equals(path) || "6".equals(path) || "7".equals(path)))) { + postListCustomPathProcess(list, mainFragmentViewModel); } return new Pair<>(openmode, list); } - @Override - protected void onCancelled() { - listener.onAsyncTaskFinished(null); + private String path; + private WeakReference mainFragmentReference; + private WeakReference context; + private OpenMode openmode; + private boolean showHiddenFiles, showThumbs; + private DataUtils dataUtils = DataUtils.getInstance(); + private boolean forceReload; + + public LoadFilesListTask( + Context context, + String path, + MainFragment mainFragment, + OpenMode openmode, + boolean showThumbs, + boolean showHiddenFiles, + boolean forceReload) { + this.path = path; + this.mainFragmentReference = new WeakReference<>(mainFragment); + this.openmode = openmode; + this.context = new WeakReference<>(context); + this.showThumbs = showThumbs; + this.showHiddenFiles = showHiddenFiles; + this.forceReload = forceReload; } - @Override - protected void onProgressUpdate(Throwable... values) { + public void onProgressUpdate(Throwable... values) { for (Throwable exception : values) { if (exception instanceof SmbException) { if ("/".equals(Uri.parse(path).getPath())) { @@ -248,11 +241,6 @@ protected void onProgressUpdate(Throwable... values) { } } - @Override - protected void onPostExecute(@Nullable Pair> list) { - listener.onAsyncTaskFinished(list); - } - private List getCachedMediaList( MainActivityViewModel mainActivityViewModel) throws IllegalStateException { List list; @@ -339,8 +327,7 @@ private void postListCustomPathProcess( final Context context = this.context.get(); if (mainFragment == null || context == null) { - cancel(true); - return null; + throw new CancellationException(); } String size = ""; @@ -410,8 +397,7 @@ private List listaudio() { final Context context = this.context.get(); if (context == null) { - cancel(true); - return null; + throw new CancellationException(); } Cursor cursor = @@ -437,8 +423,7 @@ else if (cursor.getCount() > 0 && cursor.moveToFirst()) { final Context context = this.context.get(); if (context == null) { - cancel(true); - return null; + throw new CancellationException(); } ArrayList docs = new ArrayList<>(); @@ -499,8 +484,7 @@ else if (cursor.getCount() > 0 && cursor.moveToFirst()) { final Context context = this.context.get(); if (context == null) { - cancel(true); - return null; + throw new CancellationException(); } ArrayList apks = new ArrayList<>(); @@ -537,8 +521,7 @@ else if (cursor.getCount() > 0 && cursor.moveToFirst()) { private @Nullable List listRecent() { final MainFragment mainFragment = this.mainFragmentReference.get(); if (mainFragment == null) { - cancel(true); - return null; + throw new CancellationException(); } UtilsHandler utilsHandler = AppConfig.getInstance().getUtilsHandler(); @@ -566,8 +549,7 @@ else if (cursor.getCount() > 0 && cursor.moveToFirst()) { final Context context = this.context.get(); if (context == null) { - cancel(true); - return null; + throw new CancellationException(); } List recentFiles = new ArrayList<>(20); @@ -634,8 +616,7 @@ else if (cursor.getCount() > 0 && cursor.moveToFirst()) { final Context context = this.context.get(); if (context == null) { - cancel(true); - return null; + throw new CancellationException(); } TrashBin trashBin = AppConfig.getInstance().getTrashBinInstance(); @@ -729,7 +710,6 @@ private List listSmb( mainFragment.reauthenticateSmb(); } LOG.warn("failed to load smb list, authentication issue: ", e); - publishProgress(e); return null; } catch (SmbException | NullPointerException e) { LOG.warn("Failed to load smb files for path: " + path, e); @@ -863,8 +843,7 @@ private void listOtgInternal(String path, OnFileFound fileFound) { final Context context = this.context.get(); if (context == null) { - cancel(true); - return; + throw new CancellationException(); } OTGUtil.getDocumentFiles(path, context, fileFound); @@ -874,8 +853,7 @@ private void listDocumentFilesInternal(OnFileFound fileFound) { final Context context = this.context.get(); if (context == null) { - cancel(true); - return; + throw new CancellationException(); } OTGUtil.getDocumentFiles( @@ -888,8 +866,7 @@ private void listCloudInternal( final Context context = this.context.get(); if (context == null) { - cancel(true); - return; + throw new CancellationException(); } if (!CloudSheetFragment.isCloudProviderAvailable(context)) { diff --git a/app/src/main/java/com/amaze/filemanager/ui/fragments/MainFragment.java b/app/src/main/java/com/amaze/filemanager/ui/fragments/MainFragment.java index 1a52f88fdc..e3a2bddcdd 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/fragments/MainFragment.java +++ b/app/src/main/java/com/amaze/filemanager/ui/fragments/MainFragment.java @@ -37,6 +37,8 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.concurrent.CancellationException; +import java.util.concurrent.atomic.AtomicReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -98,7 +100,6 @@ import android.graphics.Color; import android.media.RingtoneManager; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; import android.provider.DocumentsContract; import android.text.TextUtils; @@ -122,6 +123,7 @@ import androidx.core.content.pm.ShortcutInfoCompat; import androidx.core.content.pm.ShortcutManagerCompat; import androidx.core.graphics.drawable.IconCompat; +import androidx.core.util.Pair; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; @@ -133,6 +135,10 @@ import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import io.reactivex.Single; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; import jcifs.smb.SmbException; import jcifs.smb.SmbFile; import kotlin.collections.ArraysKt; @@ -176,6 +182,7 @@ public class MainFragment extends Fragment private MainActivityViewModel mainActivityViewModel; private boolean hideFab = false; + private Disposable loadFilesDisposable; private final ActivityResultLauncher handleDocumentUriForRestrictedDirectories = registerForActivityResult( @@ -388,7 +395,7 @@ public void switchView() { void loadViews() { if (!isAdded() || getView() == null) return; - + if (loadFilesDisposable != null && !loadFilesDisposable.isDisposed()) return; if (mainFragmentViewModel.getCurrentPath() != null) { if (mainFragmentViewModel.getListElements().size() == 0) { loadlist( @@ -640,8 +647,6 @@ public void returnIntentResults(HybridFileParcelable[] baseFiles) { requireActivity().finish(); } - LoadFilesListTask loadFilesListTask; - /** * This loads a path into the MainFragment. * @@ -668,9 +673,9 @@ && getMainActivity().getActionModeHelper().getActionMode() != null) { mSwipeRefreshLayout.setRefreshing(true); - if (loadFilesListTask != null && loadFilesListTask.getStatus() == AsyncTask.Status.RUNNING) { + if (loadFilesDisposable != null && !loadFilesDisposable.isDisposed()) { LOG.warn("Existing load list task running, cancel current"); - loadFilesListTask.cancel(true); + loadFilesDisposable.dispose(); } OpenMode openMode = providedOpenMode; @@ -686,27 +691,68 @@ else if (actualPath.startsWith("/") openMode = OpenMode.FILE; } - loadFilesListTask = - new LoadFilesListTask( - getActivity(), - actualPath, - this, - openMode, - getBoolean(PREFERENCE_SHOW_THUMB), - getBoolean(PREFERENCE_SHOW_HIDDENFILES), - forceReload, - (data) -> { - mSwipeRefreshLayout.setRefreshing(false); - if (data != null && data.second != null) { - boolean isPathLayoutGrid = - DataUtils.getInstance().getListOrGridForPath(providedPath, DataUtils.LIST) - == DataUtils.GRID; - setListElements(data.second, back, providedPath, data.first, isPathLayoutGrid); - } else { - LOG.warn("Load list operation cancelled"); - } - }); - loadFilesListTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + startLoadFiles(openMode, forceReload, actualPath, providedPath, back); + } + + private void startLoadFiles( + OpenMode openMode, + boolean forceReload, + String actualPath, + final String providedPath, + final boolean back) { + AtomicReference task = new AtomicReference<>(); + loadFilesDisposable = + Single.>>create( + emitter -> { + task.set( + new LoadFilesListTask( + getActivity(), + actualPath, + this, + openMode, + getBoolean(PREFERENCE_SHOW_THUMB), + getBoolean(PREFERENCE_SHOW_HIDDENFILES), + forceReload)); + + try { + + Pair> result = task.get().load(); + + if (!emitter.isDisposed()) { + emitter.onSuccess(result); + } + + } catch (Throwable e) { + + if (!emitter.isDisposed()) { + emitter.onError(e); + } + } + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + data -> { + mSwipeRefreshLayout.setRefreshing(false); + if (data != null && data.second != null) { + boolean isPathLayoutGrid = + DataUtils.getInstance().getListOrGridForPath(providedPath, DataUtils.LIST) + == DataUtils.GRID; + + setListElements(data.second, back, providedPath, data.first, isPathLayoutGrid); + } + }, + error -> { + mSwipeRefreshLayout.setRefreshing(false); + if (task.get() != null) { + task.get().onProgressUpdate(error); + } + if (error instanceof CancellationException) { + LOG.warn("Load list operation cancelled"); + } else { + LOG.error("Failed to load files", error); + } + }); } @RequiresApi(api = Q) @@ -814,7 +860,6 @@ void initNoFileLayout() { * @param back if we're coming back from any directory and want the scroll to be restored * @param path the path for the adapter * @param openMode the type of file being created - * @param results is the list of elements a result from search * @param grid whether to set grid view or list view */ public void setListElements( @@ -1383,6 +1428,14 @@ public void onDestroy() { // please move code to onStop } + @Override + public void onDestroyView() { + if (loadFilesDisposable != null) { + loadFilesDisposable.dispose(); + } + super.onDestroyView(); + } + public void hide(String path) { DataUtils.getInstance().addHiddenFile(path); File file = new File(path);