From 6a94feaf0ee00c86e8c6935c241792393067f216 Mon Sep 17 00:00:00 2001 From: Paul Akhamiogu Date: Wed, 25 Aug 2021 00:37:18 +0100 Subject: [PATCH 01/18] first attempt --- app/build.gradle | 3 +- .../filemanager/pro/extensions/Context.kt | 3 +- .../pro/fragments/ItemsFragment.kt | 61 +++++++++++++++---- settings.gradle | 2 + 4 files changed, 54 insertions(+), 15 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7e6382db..3efe573d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -58,7 +58,8 @@ android { } dependencies { - implementation 'com.github.SimpleMobileTools:Simple-Commons:16ae1d2c03' +// implementation 'com.github.SimpleMobileTools:Simple-Commons:e56c724d04' + implementation project(":commons") implementation 'com.github.Stericson:RootTools:df729dcb13' implementation 'com.github.Stericson:RootShell:1.6' implementation 'com.alexvasilkov:gesture-views:2.5.2' diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/extensions/Context.kt index 07b1f5f5..0e30de4a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/extensions/Context.kt @@ -3,8 +3,9 @@ package com.simplemobiletools.filemanager.pro.extensions import android.content.Context import com.simplemobiletools.commons.extensions.isPathOnOTG import com.simplemobiletools.commons.extensions.isPathOnSD +import com.simplemobiletools.commons.extensions.otgPath +import com.simplemobiletools.commons.extensions.sdCardPath import com.simplemobiletools.filemanager.pro.helpers.Config val Context.config: Config get() = Config.newInstance(applicationContext) - fun Context.isPathOnRoot(path: String) = !(path.startsWith(config.internalStoragePath) || isPathOnOTG(path) || (isPathOnSD(path))) diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt index e935585a..4e6d22b3 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt @@ -3,6 +3,7 @@ package com.simplemobiletools.filemanager.pro.fragments import android.content.Context import android.os.Parcelable import android.util.AttributeSet +import android.util.Log import androidx.recyclerview.widget.GridLayoutManager import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.dialogs.StoragePickerDialog @@ -23,12 +24,13 @@ import com.simplemobiletools.filemanager.pro.helpers.MAX_COLUMN_COUNT import com.simplemobiletools.filemanager.pro.helpers.RootHelpers import com.simplemobiletools.filemanager.pro.interfaces.ItemOperationsListener import com.simplemobiletools.filemanager.pro.models.ListItem -import kotlinx.android.synthetic.main.items_fragment.view.* import java.io.File import java.util.* import kotlin.collections.ArrayList +import kotlinx.android.synthetic.main.items_fragment.view.* -class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet), ItemOperationsListener, Breadcrumbs.BreadcrumbsListener { +class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet), ItemOperationsListener, + Breadcrumbs.BreadcrumbsListener { private var showHidden = false private var skipItemUpdating = false private var isSearchOpen = false @@ -156,18 +158,47 @@ class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerF private fun getItems(path: String, callback: (originalPath: String, items: ArrayList) -> Unit) { skipItemUpdating = false - ensureBackgroundThread { - if (activity?.isDestroyed == false && activity?.isFinishing == false) { - val config = context!!.config - if (context!!.isPathOnOTG(path) && config.OTGTreeUri.isNotEmpty()) { - val getProperFileSize = context!!.config.getFolderSorting(currentPath) and SORT_BY_SIZE != 0 - context!!.getOTGItems(path, config.shouldShowHidden, getProperFileSize) { - callback(path, getListItemsFromFileDirItems(it)) + Log.d(TAG, "getItems: $path") + + if (isRPlus() && context.isAndroidDataRoot(path)) { + activity?.handleSAFDialog(path) { granted -> + Log.d(TAG, "getItems: $granted") + if (!granted) { + return@handleSAFDialog + } + ensureBackgroundThread { + if (activity?.isDestroyed == false && activity?.isFinishing == false) { + val config = context!!.config + if (context!!.isPathOnOTG(path) && config.OTGTreeUri.isNotEmpty()) { + val getProperFileSize = context!!.config.getFolderSorting(currentPath) and SORT_BY_SIZE != 0 + context!!.getOTGItems(path, config.shouldShowHidden, getProperFileSize) { + callback(path, getListItemsFromFileDirItems(it)) + } + }else if (!config.enableRootAccess || !context!!.isPathOnRoot(path)) { + val getProperFileSize = context!!.config.getFolderSorting(currentPath) and SORT_BY_SIZE != 0 + context!!.getStorageItems(path, config.shouldShowHidden, getProperFileSize){ + callback(path, getListItemsFromFileDirItems(it)) + } + } else { + RootHelpers(activity!!).getFiles(path, callback) + } + } + } + } + } else { + ensureBackgroundThread { + if (activity?.isDestroyed == false && activity?.isFinishing == false) { + val config = context!!.config + if (context!!.isPathOnOTG(path) && config.OTGTreeUri.isNotEmpty()) { + val getProperFileSize = context!!.config.getFolderSorting(currentPath) and SORT_BY_SIZE != 0 + context!!.getOTGItems(path, config.shouldShowHidden, getProperFileSize) { + callback(path, getListItemsFromFileDirItems(it)) + } + } else if (!config.enableRootAccess || !context!!.isPathOnRoot(path)) { + getRegularItemsOf(path, callback) + } else { + RootHelpers(activity!!).getFiles(path, callback) } - } else if (!config.enableRootAccess || !context!!.isPathOnRoot(path)) { - getRegularItemsOf(path, callback) - } else { - RootHelpers(activity!!).getFiles(path, callback) } } } @@ -526,4 +557,8 @@ class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerF override fun selectedPaths(paths: ArrayList) { (activity as MainActivity).pickedPaths(paths) } + + companion object { + private const val TAG = "ItemsFragment" + } } diff --git a/settings.gradle b/settings.gradle index e7b4def4..772c2522 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,3 @@ include ':app' +include ':commons' +project(":commons").projectDir = new File("/Users/cyberman/StudioProjects/Simple-Commons/commons") From 471d77e19f76ab768cafdbfd1f1a163488cd338a Mon Sep 17 00:00:00 2001 From: darthpaul Date: Sat, 23 Oct 2021 23:03:34 +0100 Subject: [PATCH 02/18] read files from Andoid/data and Android/obb --- .../pro/fragments/ItemsFragment.kt | 110 ++++++++---------- 1 file changed, 46 insertions(+), 64 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt index 55d4187b..0468818a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt @@ -3,7 +3,6 @@ package com.simplemobiletools.filemanager.pro.fragments import android.content.Context import android.os.Parcelable import android.util.AttributeSet -import android.util.Log import androidx.recyclerview.widget.GridLayoutManager import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.dialogs.StoragePickerDialog @@ -120,8 +119,10 @@ class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerF breadcrumbs.updateFontSize(context!!.getTextSize()) } - ItemsAdapter(activity as SimpleActivity, storedItems, this, items_list, isPickMultipleIntent, items_fastscroller, - items_swipe_refresh) { + ItemsAdapter( + activity as SimpleActivity, storedItems, this, items_list, isPickMultipleIntent, items_fastscroller, + items_swipe_refresh + ) { if ((it as? ListItem)?.isSectionTitle == true) { openDirectory(it.mPath) searchClosed() @@ -158,47 +159,18 @@ class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerF private fun getItems(path: String, callback: (originalPath: String, items: ArrayList) -> Unit) { skipItemUpdating = false - Log.d(TAG, "getItems: $path") - - if (isRPlus() && context.isAndroidDataRoot(path)) { - activity?.handleSAFDialog(path) { granted -> - Log.d(TAG, "getItems: $granted") - if (!granted) { - return@handleSAFDialog - } - ensureBackgroundThread { - if (activity?.isDestroyed == false && activity?.isFinishing == false) { - val config = context!!.config - if (context!!.isPathOnOTG(path) && config.OTGTreeUri.isNotEmpty()) { - val getProperFileSize = context!!.config.getFolderSorting(currentPath) and SORT_BY_SIZE != 0 - context!!.getOTGItems(path, config.shouldShowHidden, getProperFileSize) { - callback(path, getListItemsFromFileDirItems(it)) - } - }else if (!config.enableRootAccess || !context!!.isPathOnRoot(path)) { - val getProperFileSize = context!!.config.getFolderSorting(currentPath) and SORT_BY_SIZE != 0 - context!!.getStorageItems(path, config.shouldShowHidden, getProperFileSize){ - callback(path, getListItemsFromFileDirItems(it)) - } - } else { - RootHelpers(activity!!).getFiles(path, callback) - } - } - } - } - } else { - ensureBackgroundThread { - if (activity?.isDestroyed == false && activity?.isFinishing == false) { - val config = context!!.config - if (context!!.isPathOnOTG(path) && config.OTGTreeUri.isNotEmpty()) { - val getProperFileSize = context!!.config.getFolderSorting(currentPath) and SORT_BY_SIZE != 0 - context!!.getOTGItems(path, config.shouldShowHidden, getProperFileSize) { - callback(path, getListItemsFromFileDirItems(it)) - } - } else if (!config.enableRootAccess || !context!!.isPathOnRoot(path)) { - getRegularItemsOf(path, callback) - } else { - RootHelpers(activity!!).getFiles(path, callback) + ensureBackgroundThread { + if (activity?.isDestroyed == false && activity?.isFinishing == false) { + val config = context!!.config + if (context!!.isPathOnOTG(path) && config.OTGTreeUri.isNotEmpty()) { + val getProperFileSize = context!!.config.getFolderSorting(currentPath) and SORT_BY_SIZE != 0 + context!!.getOTGItems(path, config.shouldShowHidden, getProperFileSize) { + callback(path, getListItemsFromFileDirItems(it)) } + } else if (!config.enableRootAccess || !context!!.isPathOnRoot(path)) { + getRegularItemsOf(path, callback) + } else { + RootHelpers(activity!!).getFiles(path, callback) } } } @@ -206,33 +178,47 @@ class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerF private fun getRegularItemsOf(path: String, callback: (originalPath: String, items: ArrayList) -> Unit) { val items = ArrayList() - val files = File(path).listFiles()?.filterNotNull() - if (context == null || files == null) { + + if (context == null) { callback(path, items) return } val isSortingBySize = context!!.config.getFolderSorting(currentPath) and SORT_BY_SIZE != 0 val getProperChildCount = context!!.config.getFolderViewType(currentPath) == VIEW_TYPE_LIST - val lastModifieds = context!!.getFolderLastModifieds(path) - for (file in files) { - val fileDirItem = getFileDirItemFromFile(file, isSortingBySize, lastModifieds, false) - if (fileDirItem != null) { - items.add(fileDirItem) + if (isRPlus() && context.isSAFOnlyRoot(path)) { + activity?.handlePrimarySAFDialog(path) { + context.getStorageItemsWithTreeUri(path, context.config.shouldShowHidden, getProperChildCount) { + callback(path, getListItemsFromFileDirItems(it)) + } } - } + } else { + val files = File(path).listFiles()?.filterNotNull() + if (files == null) { + callback(path, items) + return + } + val lastModifieds = context!!.getFolderLastModifieds(path) - // send out the initial item list asap, get proper child count asynchronously as it can be slow - callback(path, items) + for (file in files) { + val fileDirItem = getFileDirItemFromFile(file, isSortingBySize, lastModifieds, false) + if (fileDirItem != null) { + items.add(fileDirItem) + } + } - if (getProperChildCount) { - items.filter { it.mIsDirectory }.forEach { - if (context != null) { - val childrenCount = it.getDirectChildrenCount(context!!, showHidden) - if (childrenCount != 0) { - activity?.runOnUiThread { - getRecyclerAdapter()?.updateChildCount(it.mPath, childrenCount) + // send out the initial item list asap, get proper child count asynchronously as it can be slow + callback(path, items) + + if (getProperChildCount) { + items.filter { it.mIsDirectory }.forEach { + if (context != null) { + val childrenCount = it.getDirectChildrenCount(context!!, showHidden) + if (childrenCount != 0) { + activity?.runOnUiThread { + getRecyclerAdapter()?.updateChildCount(it.mPath, childrenCount) + } } } } @@ -557,8 +543,4 @@ class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerF override fun selectedPaths(paths: ArrayList) { (activity as MainActivity).pickedPaths(paths) } - - companion object { - private const val TAG = "ItemsFragment" - } } From 644842322b7ff73da04d2db19598d310b800f673 Mon Sep 17 00:00:00 2001 From: darthpaul Date: Thu, 28 Oct 2021 23:46:22 +0100 Subject: [PATCH 03/18] read handle create file/directory --- .../pro/dialogs/CreateNewItemDialog.kt | 82 ++++++++++++------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt index 2131dd0d..170d994b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt @@ -3,6 +3,7 @@ package com.simplemobiletools.filemanager.pro.dialogs import android.view.View import androidx.appcompat.app.AlertDialog import com.simplemobiletools.commons.extensions.* +import com.simplemobiletools.commons.helpers.isRPlus import com.simplemobiletools.filemanager.pro.R import com.simplemobiletools.filemanager.pro.activities.SimpleActivity import com.simplemobiletools.filemanager.pro.helpers.RootHelpers @@ -15,37 +16,37 @@ class CreateNewItemDialog(val activity: SimpleActivity, val path: String, val ca init { AlertDialog.Builder(activity) - .setPositiveButton(R.string.ok, null) - .setNegativeButton(R.string.cancel, null) - .create().apply { - activity.setupDialogStuff(view, this, R.string.create_new) { - showKeyboard(view.item_name) - getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(View.OnClickListener { - val name = view.item_name.value - if (name.isEmpty()) { - activity.toast(R.string.empty_name) - } else if (name.isAValidFilename()) { - val newPath = "$path/$name" - if (activity.getDoesFilePathExist(newPath)) { - activity.toast(R.string.name_taken) - return@OnClickListener - } + .setPositiveButton(R.string.ok, null) + .setNegativeButton(R.string.cancel, null) + .create().apply { + activity.setupDialogStuff(view, this, R.string.create_new) { + showKeyboard(view.item_name) + getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(View.OnClickListener { + val name = view.item_name.value + if (name.isEmpty()) { + activity.toast(R.string.empty_name) + } else if (name.isAValidFilename()) { + val newPath = "$path/$name" + if (activity.getDoesFilePathExist(newPath)) { + activity.toast(R.string.name_taken) + return@OnClickListener + } - if (view.dialog_radio_group.checkedRadioButtonId == R.id.dialog_radio_directory) { - createDirectory(newPath, this) { - callback(it) - } - } else { - createFile(newPath, this) { - callback(it) - } + if (view.dialog_radio_group.checkedRadioButtonId == R.id.dialog_radio_directory) { + createDirectory(newPath, this) { + callback(it) } } else { - activity.toast(R.string.invalid_name) + createFile(newPath, this) { + callback(it) + } } - }) - } + } else { + activity.toast(R.string.invalid_name) + } + }) } + } } private fun createDirectory(path: String, alertDialog: AlertDialog, callback: (Boolean) -> Unit) { @@ -66,8 +67,18 @@ class CreateNewItemDialog(val activity: SimpleActivity, val path: String, val ca success(alertDialog) } path.startsWith(activity.internalStoragePath, true) -> { - if (File(path).mkdirs()) { - success(alertDialog) + if (isRPlus() && activity.isSAFOnlyRoot(path)) { + if (activity.createSAFOnlyDirectory(path)) { + success(alertDialog) + } else { + val error = String.format(activity.getString(R.string.could_not_create_folder), path) + activity.showErrorToast(error) + callback(false) + } + } else { + if (File(path).mkdirs()) { + success(alertDialog) + } } } else -> { @@ -103,9 +114,20 @@ class CreateNewItemDialog(val activity: SimpleActivity, val path: String, val ca } } path.startsWith(activity.internalStoragePath, true) -> { - if (File(path).createNewFile()) { - success(alertDialog) + if (isRPlus() && activity.isSAFOnlyRoot(path)) { + if (activity.createSAFOnlyFile(path)) { + success(alertDialog) + } else { + val error = String.format(activity.getString(R.string.could_not_create_file), path) + activity.showErrorToast(error) + callback(false) + } + } else { + if (File(path).createNewFile()) { + success(alertDialog) + } } + } else -> { RootHelpers(activity).createFileFolder(path, true) { From 26d79d5f4afa732ff3d250ffb5db721186c01308 Mon Sep 17 00:00:00 2001 From: darthpaul Date: Sun, 31 Oct 2021 10:05:50 +0000 Subject: [PATCH 04/18] handle MANAGE_EXTERNAL_STORAGE permission for >=API 30 --- app/src/main/AndroidManifest.xml | 1 + .../pro/activities/MainActivity.kt | 50 +++++++++++++++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a7adeefd..e9f14943 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ + 1 } @@ -268,8 +275,8 @@ class MainActivity : SimpleActivity() { } private fun tryInitFileManager() { - val hadPermission = hasPermission(PERMISSION_WRITE_STORAGE) - handlePermission(PERMISSION_WRITE_STORAGE) { + val hadPermission = hasStoragePermission() + handleStoragePermission { checkOTGPath() if (it) { if (main_view_pager.adapter == null) { @@ -286,6 +293,43 @@ class MainActivity : SimpleActivity() { } } + private fun handleStoragePermission(callback: (granted: Boolean) -> Unit) { + actionOnPermission = null + if (hasStoragePermission()) { + callback(true) + } else { + if (isRPlus()) { + isAskingPermissions = true + actionOnPermission = callback + try { + val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) + intent.addCategory("android.intent.category.DEFAULT") + intent.data = Uri.parse(String.format("package:%s", applicationContext.packageName)) + startActivityForResult(intent, MANAGE_STORAGE_RC) + } catch (e: Exception) { + e.printStackTrace() + val intent = Intent() + intent.action = Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION + startActivityForResult(intent, MANAGE_STORAGE_RC) + } + } else { + handlePermission(PERMISSION_WRITE_STORAGE, callback) + } + } + } + + private fun hasStoragePermission(): Boolean { + return if (isRPlus()) Environment.isExternalStorageManager() else hasPermission(PERMISSION_WRITE_STORAGE) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { + super.onActivityResult(requestCode, resultCode, resultData) + isAskingPermissions = false + if(requestCode == MANAGE_STORAGE_RC && isRPlus()){ + actionOnPermission?.invoke(Environment.isExternalStorageManager()) + } + } + private fun initFileManager(refreshRecents: Boolean) { if (intent.action == Intent.ACTION_VIEW && intent.data != null) { val data = intent.data From 6dbfdb0c24cd5d14afb44c993a3ca27dc9ace614 Mon Sep 17 00:00:00 2001 From: darthpaul Date: Tue, 2 Nov 2021 07:45:33 +0000 Subject: [PATCH 05/18] handle copy/move, share, create new directory --- .../pro/activities/MainActivity.kt | 4 +- .../filemanager/pro/adapters/ItemsAdapter.kt | 57 ++++++++++++++----- .../pro/dialogs/CreateNewItemDialog.kt | 55 +++++++++++------- .../pro/fragments/ItemsFragment.kt | 6 +- 4 files changed, 81 insertions(+), 41 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/MainActivity.kt index 89aa76e4..d3e29a79 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/MainActivity.kt @@ -304,7 +304,7 @@ class MainActivity : SimpleActivity() { try { val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) intent.addCategory("android.intent.category.DEFAULT") - intent.data = Uri.parse(String.format("package:%s", applicationContext.packageName)) + intent.data = Uri.parse("package:$packageName") startActivityForResult(intent, MANAGE_STORAGE_RC) } catch (e: Exception) { e.printStackTrace() @@ -325,7 +325,7 @@ class MainActivity : SimpleActivity() { override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { super.onActivityResult(requestCode, resultCode, resultData) isAskingPermissions = false - if(requestCode == MANAGE_STORAGE_RC && isRPlus()){ + if (requestCode == MANAGE_STORAGE_RC && isRPlus()) { actionOnPermission?.invoke(Environment.isExternalStorageManager()) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt index 48caa7a5..dc332ffa 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt @@ -327,13 +327,25 @@ class ItemsAdapter(activity: SimpleActivity, var listItems: MutableList) { if (activity.getIsPathDirectory(path)) { val shouldShowHidden = activity.config.shouldShowHidden - if (activity.isPathOnOTG(path)) { - activity.getDocumentFile(path)?.listFiles()?.filter { if (shouldShowHidden) true else !it.name!!.startsWith(".") }?.forEach { - addFileUris(it.uri.toString(), paths) + when { + activity.isRestrictedAndroidDir(path) -> { + activity.getStorageItemsWithTreeUri(path, shouldShowHidden, false){ files-> + files.forEach { + addFileUris(activity.getPrimaryAndroidSAFUri(it.path).toString(), paths) + } + } } - } else { - File(path).listFiles()?.filter { if (shouldShowHidden) true else !it.name.startsWith('.') }?.forEach { - addFileUris(it.absolutePath, paths) + + activity.isPathOnOTG(path) -> { + activity.getDocumentFile(path)?.listFiles()?.filter { if (shouldShowHidden) true else !it.name!!.startsWith(".") }?.forEach { + addFileUris(it.uri.toString(), paths) + } + } + + else -> { + File(path).listFiles()?.filter { if (shouldShowHidden) true else !it.name.startsWith('.') }?.forEach { + addFileUris(it.absolutePath, paths) + } } } } else { @@ -363,7 +375,8 @@ class ItemsAdapter(activity: SimpleActivity, var listItems: MutableList - val sourceFile = File(sourceFileDir.path) - if (activity.getDoesFilePathExist(source) && activity.getIsPathDirectory(source) && - sourceFile.list()?.isEmpty() == true && sourceFile.getProperSize(true) == 0L && sourceFile.getFileCount(true) == 0) { - val sourceFolder = sourceFile.toFileDirItem(activity) - activity.deleteFile(sourceFolder, true) { + val sourcePath = sourceFileDir.path + if (activity.isRestrictedAndroidDir(sourcePath) && activity.getDoesFilePathExist(sourcePath)) { + activity.deleteFile(sourceFileDir, true) { listener?.refreshItems() activity.runOnUiThread { finishActMode() } } } else { - listener?.refreshItems() - finishActMode() + val sourceFile = File(sourcePath) + if (activity.getDoesFilePathExist(source) && activity.getIsPathDirectory(source) && + sourceFile.list()?.isEmpty() == true && sourceFile.getProperSize(true) == 0L && sourceFile.getFileCount(true) == 0 + ) { + val sourceFolder = sourceFile.toFileDirItem(activity) + activity.deleteFile(sourceFolder, true) { + listener?.refreshItems() + activity.runOnUiThread { + finishActMode() + } + } + } else { + listener?.refreshItems() + finishActMode() + } } } } else { @@ -828,10 +852,13 @@ class ItemsAdapter(activity: SimpleActivity, var listItems: MutableList { - if (isRPlus() && activity.isSAFOnlyRoot(path)) { - if (activity.createSAFOnlyDirectory(path)) { - success(alertDialog) - } else { - val error = String.format(activity.getString(R.string.could_not_create_folder), path) - activity.showErrorToast(error) - callback(false) + if (activity.isRestrictedAndroidDir(path)) { + activity.handlePrimarySAFDialog(path) { + if (!it) { + callback(false) + return@handlePrimarySAFDialog + } + if (activity.createSAFOnlyDirectory(path)) { + success(alertDialog) + } else { + val error = String.format(activity.getString(R.string.could_not_create_folder), path) + activity.showErrorToast(error) + callback(false) + } } } else { if (File(path).mkdirs()) { @@ -96,6 +102,22 @@ class CreateNewItemDialog(val activity: SimpleActivity, val path: String, val ca private fun createFile(path: String, alertDialog: AlertDialog, callback: (Boolean) -> Unit) { try { when { + activity.isRestrictedAndroidDir(path) -> { + activity.handlePrimarySAFDialog(path) { + if (!it) { + callback(false) + return@handlePrimarySAFDialog + } + if (activity.createSAFOnlyFile(path)) { + success(alertDialog) + } else { + val error = String.format(activity.getString(R.string.could_not_create_file), path) + activity.showErrorToast(error) + callback(false) + } + } + } + activity.needsStupidWritePermissions(path) -> { activity.handleSAFDialog(path) { if (!it) { @@ -113,22 +135,13 @@ class CreateNewItemDialog(val activity: SimpleActivity, val path: String, val ca success(alertDialog) } } - path.startsWith(activity.internalStoragePath, true) -> { - if (isRPlus() && activity.isSAFOnlyRoot(path)) { - if (activity.createSAFOnlyFile(path)) { - success(alertDialog) - } else { - val error = String.format(activity.getString(R.string.could_not_create_file), path) - activity.showErrorToast(error) - callback(false) - } - } else { - if (File(path).createNewFile()) { - success(alertDialog) - } - } + path.startsWith(activity.internalStoragePath, true) -> { + if (File(path).createNewFile()) { + success(alertDialog) + } } + else -> { RootHelpers(activity).createFileFolder(path, true) { if (it) { diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt index 0468818a..8174e4d0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt @@ -187,7 +187,7 @@ class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerF val isSortingBySize = context!!.config.getFolderSorting(currentPath) and SORT_BY_SIZE != 0 val getProperChildCount = context!!.config.getFolderViewType(currentPath) == VIEW_TYPE_LIST - if (isRPlus() && context.isSAFOnlyRoot(path)) { + if (context.isRestrictedAndroidDir(path)) { activity?.handlePrimarySAFDialog(path) { context.getStorageItemsWithTreeUri(path, context.config.shouldShowHidden, getProperChildCount) { callback(path, getListItemsFromFileDirItems(it)) @@ -214,7 +214,7 @@ class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerF if (getProperChildCount) { items.filter { it.mIsDirectory }.forEach { if (context != null) { - val childrenCount = it.getDirectChildrenCount(context!!, showHidden) + val childrenCount = it.getDirectChildrenCount(activity as BaseSimpleActivity, showHidden) if (childrenCount != 0) { activity?.runOnUiThread { getRecyclerAdapter()?.updateChildCount(it.mPath, childrenCount) @@ -235,7 +235,7 @@ class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerF var lastModified = lastModifieds.remove(curPath) val isDirectory = if (lastModified != null) false else file.isDirectory - val children = if (isDirectory && getProperChildCount) file.getDirectChildrenCount(showHidden) else 0 + val children = if (isDirectory && getProperChildCount) file.getDirectChildrenCount(context, showHidden) else 0 val size = if (isDirectory) { if (isSortingBySize) { file.getProperSize(showHidden) From 1e067e36142267b09382c9ca32c6766ad9724759 Mon Sep 17 00:00:00 2001 From: darthpaul Date: Tue, 2 Nov 2021 21:49:21 +0000 Subject: [PATCH 06/18] handle compress/decompress --- .../filemanager/pro/adapters/ItemsAdapter.kt | 232 ++++++++++-------- 1 file changed, 135 insertions(+), 97 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt index dc332ffa..3b1a8493 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt @@ -41,6 +41,7 @@ import com.simplemobiletools.filemanager.pro.helpers.* import com.simplemobiletools.filemanager.pro.interfaces.ItemOperationsListener import com.simplemobiletools.filemanager.pro.models.ListItem import com.stericson.RootTools.RootTools +import java.io.BufferedInputStream import kotlinx.android.synthetic.main.item_file_dir_grid.view.* import kotlinx.android.synthetic.main.item_file_dir_list.view.* import kotlinx.android.synthetic.main.item_file_dir_list.view.item_frame @@ -50,13 +51,18 @@ import kotlinx.android.synthetic.main.item_section.view.* import java.io.Closeable import java.io.File import java.io.FileInputStream +import java.net.URI +import java.net.URLEncoder import java.util.* import java.util.zip.ZipEntry import java.util.zip.ZipFile +import java.util.zip.ZipInputStream import java.util.zip.ZipOutputStream -class ItemsAdapter(activity: SimpleActivity, var listItems: MutableList, val listener: ItemOperationsListener?, recyclerView: MyRecyclerView, - val isPickMultipleIntent: Boolean, fastScroller: FastScroller?, val swipeRefreshLayout: SwipeRefreshLayout, itemClick: (Any) -> Unit) : +class ItemsAdapter( + activity: SimpleActivity, var listItems: MutableList, val listener: ItemOperationsListener?, recyclerView: MyRecyclerView, + val isPickMultipleIntent: Boolean, fastScroller: FastScroller?, val swipeRefreshLayout: SwipeRefreshLayout, itemClick: (Any) -> Unit +) : MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) { private val TYPE_FILE_DIR = 1 @@ -329,7 +335,7 @@ class ItemsAdapter(activity: SimpleActivity, var listItems: MutableList { - activity.getStorageItemsWithTreeUri(path, shouldShowHidden, false){ files-> + activity.getStorageItemsWithTreeUri(path, shouldShowHidden, false) { files -> files.forEach { addFileUris(activity.getPrimaryAndroidSAFUri(it.path).toString(), paths) } @@ -463,22 +469,27 @@ class ItemsAdapter(activity: SimpleActivity, var listItems: MutableList + if (!granted) { + return@handlePrimarySAFDialog } + activity.handleSAFDialog(firstPath) { + if (!it) { + return@handleSAFDialog + } - activity.toast(R.string.compressing) - val paths = getSelectedFileDirItems().map { it.path } - ensureBackgroundThread { - if (compressPaths(paths, destination)) { - activity.runOnUiThread { - activity.toast(R.string.compression_successful) - listener?.refreshItems() - finishActMode() + activity.toast(R.string.compressing) + val paths = getSelectedFileDirItems().map { it.path } + ensureBackgroundThread { + if (compressPaths(paths, destination)) { + activity.runOnUiThread { + activity.toast(R.string.compression_successful) + listener?.refreshItems() + finishActMode() + } + } else { + activity.toast(R.string.compressing_failed) } - } else { - activity.toast(R.string.compressing_failed) } } } @@ -513,88 +524,94 @@ class ItemsAdapter(activity: SimpleActivity, var listItems: MutableList, callback: (success: Boolean) -> Unit) { - sourcePaths.forEach { - try { - val zipFile = ZipFile(it) - val entries = zipFile.entries() - val fileDirItems = ArrayList() - while (entries.hasMoreElements()) { - val entry = entries.nextElement() - val currPath = if (entry.isDirectory) it else "${it.getParentPath().trimEnd('/')}/${entry.name}" - val fileDirItem = FileDirItem(currPath, entry.name, entry.isDirectory, 0, entry.size) - fileDirItems.add(fileDirItem) - } - - val destinationPath = fileDirItems.first().getParentPath().trimEnd('/') - activity.checkConflicts(fileDirItems, destinationPath, 0, LinkedHashMap()) { - ensureBackgroundThread { - decompressPaths(sourcePaths, it, callback) + sourcePaths.forEach { path -> + val zipInputStream = ZipInputStream(BufferedInputStream(activity.getFileInputStreamSync(path))) + zipInputStream.use { + try { + val fileDirItems = ArrayList() + var entry = zipInputStream.nextEntry + while (entry != null) { + val currPath = if (entry.isDirectory) path else "${path.getParentPath().trimEnd('/')}/${entry.name}" + val fileDirItem = FileDirItem(currPath, entry.name, entry.isDirectory, 0, entry.size) + fileDirItems.add(fileDirItem) + zipInputStream.closeEntry() + entry = zipInputStream.nextEntry } + zipInputStream.closeEntry() + val destinationPath = fileDirItems.first().getParentPath().trimEnd('/') + activity.checkConflicts(fileDirItems, destinationPath, 0, LinkedHashMap()) { + ensureBackgroundThread { + decompressPaths(sourcePaths, it, callback) + } + } + } catch (exception: Exception) { + exception.printStackTrace() + activity.showErrorToast(exception) } - } catch (exception: Exception) { - activity.showErrorToast(exception) } } } private fun decompressPaths(paths: List, conflictResolutions: LinkedHashMap, callback: (success: Boolean) -> Unit) { - paths.forEach { - try { - val zipFile = ZipFile(it) - val entries = zipFile.entries() - val zipFileName = it.getFilenameFromPath() - val newFolderName = zipFileName.subSequence(0, zipFileName.length - 4) - while (entries.hasMoreElements()) { - val entry = entries.nextElement() - val parentPath = it.getParentPath() - val newPath = "$parentPath/$newFolderName/${entry.name.trimEnd('/')}" + paths.forEach { path -> + val zipInputStream = ZipInputStream(BufferedInputStream(activity.getFileInputStreamSync(path))) + zipInputStream.use { + try { + var entry = zipInputStream.nextEntry + val zipFileName = path.getFilenameFromPath() + val newFolderName = zipFileName.subSequence(0, zipFileName.length - 4) + while (entry != null) { + val parentPath = path.getParentPath() + val newPath = "$parentPath/$newFolderName/${entry.name.trimEnd('/')}" - val resolution = getConflictResolution(conflictResolutions, newPath) - val doesPathExist = activity.getDoesFilePathExist(newPath) - if (doesPathExist && resolution == CONFLICT_OVERWRITE) { - val fileDirItem = FileDirItem(newPath, newPath.getFilenameFromPath(), entry.isDirectory) - if (activity.getIsPathDirectory(it)) { - activity.deleteFolderBg(fileDirItem, false) { - if (it) { - extractEntry(newPath, entry, zipFile) - } else { - callback(false) - } - } - } else { - activity.deleteFileBg(fileDirItem, false) { - if (it) { - extractEntry(newPath, entry, zipFile) - } else { - callback(false) + val resolution = getConflictResolution(conflictResolutions, newPath) + val doesPathExist = activity.getDoesFilePathExist(newPath) + if (doesPathExist && resolution == CONFLICT_OVERWRITE) { + val fileDirItem = FileDirItem(newPath, newPath.getFilenameFromPath(), entry.isDirectory) + if (activity.getIsPathDirectory(path)) { + activity.deleteFolderBg(fileDirItem, false) { + if (it) { + extractEntry(newPath, entry, zipInputStream) + } else { + callback(false) + } + } + } else { + activity.deleteFileBg(fileDirItem, false) { + if (it) { + extractEntry(newPath, entry, zipInputStream) + } else { + callback(false) + } } } + } else if (!doesPathExist) { + extractEntry(newPath, entry, zipInputStream) } - } else if (!doesPathExist) { - extractEntry(newPath, entry, zipFile) + + zipInputStream.closeEntry() + entry = zipInputStream.nextEntry } + callback(true) + } catch (e: Exception) { + e.printStackTrace() + activity.showErrorToast(e) + callback(false) } - callback(true) - } catch (e: Exception) { - activity.showErrorToast(e) - callback(false) } } } - private fun extractEntry(newPath: String, entry: ZipEntry, zipFile: ZipFile) { + private fun extractEntry(newPath: String, entry: ZipEntry, zipInputStream: ZipInputStream) { if (entry.isDirectory) { if (!activity.createDirectorySync(newPath) && !activity.getDoesFilePathExist(newPath)) { val error = String.format(activity.getString(R.string.could_not_create_file), newPath) activity.showErrorToast(error) } } else { - val ins = zipFile.getInputStream(entry) - ins.use { - val fos = activity.getFileOutputStreamSync(newPath, newPath.getMimeType()) - if (fos != null) { - ins.copyTo(fos) - } + val fos = activity.getFileOutputStreamSync(newPath, newPath.getMimeType()) + if (fos != null) { + zipInputStream.copyTo(fos) } } } @@ -610,48 +627,68 @@ class ItemsAdapter(activity: SimpleActivity, var listItems: MutableList, targetPath: String): Boolean { - val queue = LinkedList() + val queue = LinkedList() val fos = activity.getFileOutputStreamSync(targetPath, "application/zip") ?: return false val zout = ZipOutputStream(fos) var res: Closeable = fos try { - sourcePaths.forEach { + sourcePaths.forEach { currentPath -> var name: String - var mainFile = File(it) - val base = mainFile.parentFile.toURI() + var mainFilePath = currentPath + val base = "${mainFilePath.getParentPath()}/" res = zout - queue.push(mainFile) - if (activity.getIsPathDirectory(mainFile.absolutePath)) { - name = "${mainFile.name.trimEnd('/')}/" + queue.push(mainFilePath) + if (activity.getIsPathDirectory(mainFilePath)) { + name = "${mainFilePath.getFilenameFromPath()}/" zout.putNextEntry(ZipEntry(name)) } while (!queue.isEmpty()) { - mainFile = queue.pop() - if (activity.getIsPathDirectory(mainFile.absolutePath)) { - for (file in mainFile.listFiles()) { - name = base.relativize(file.toURI()).path - if (activity.getIsPathDirectory(file.absolutePath)) { - queue.push(file) - name = "${name.trimEnd('/')}/" - zout.putNextEntry(ZipEntry(name)) - } else { - zout.putNextEntry(ZipEntry(name)) - FileInputStream(file).copyTo(zout) - zout.closeEntry() + mainFilePath = queue.pop() + if (activity.getIsPathDirectory(mainFilePath)) { + if (activity.isRestrictedAndroidDir(mainFilePath)) { + activity.getStorageItemsWithTreeUri(mainFilePath, true) { files -> + for (file in files) { + name = file.path.relativizeWith(base) + if (activity.getIsPathDirectory(file.path)) { + queue.push(file.path) + name = "${name.trimEnd('/')}/" + zout.putNextEntry(ZipEntry(name)) + } else { + zout.putNextEntry(ZipEntry(name)) + activity.getFileInputStreamSync(file.path)!!.copyTo(zout) + zout.closeEntry() + } + } + } + } else { + val mainFile = File(mainFilePath) + for (file in mainFile.listFiles()) { + name = file.path.relativizeWith(base) + if (activity.getIsPathDirectory(file.absolutePath)) { + queue.push(file.absolutePath) + name = "${name.trimEnd('/')}/" + zout.putNextEntry(ZipEntry(name)) + } else { + zout.putNextEntry(ZipEntry(name)) + activity.getFileInputStreamSync(file.path)!!.copyTo(zout) + zout.closeEntry() + } } } + } else { - name = if (base.path == it) it.getFilenameFromPath() else base.relativize(mainFile.toURI()).path + name = if (base == currentPath) currentPath.getFilenameFromPath() else mainFilePath.relativizeWith(base) zout.putNextEntry(ZipEntry(name)) - FileInputStream(mainFile).copyTo(zout) + activity.getFileInputStreamSync(mainFilePath)!!.copyTo(zout) zout.closeEntry() } } } } catch (exception: Exception) { + exception.printStackTrace() activity.showErrorToast(exception) return false } finally { @@ -835,7 +872,8 @@ class ItemsAdapter(activity: SimpleActivity, var listItems: MutableList Date: Wed, 10 Nov 2021 20:46:05 +0000 Subject: [PATCH 07/18] fix query for recents fragment --- .../pro/dialogs/CreateNewItemDialog.kt | 4 +- .../pro/fragments/RecentsFragment.kt | 45 ++++++++++++++----- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt index 914bd382..e24728c1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt @@ -66,7 +66,7 @@ class CreateNewItemDialog(val activity: SimpleActivity, val path: String, val ca documentFile.createDirectory(path.getFilenameFromPath()) success(alertDialog) } - path.startsWith(activity.internalStoragePath, true) -> { + isRPlus() || path.startsWith(activity.internalStoragePath, true) -> { if (activity.isRestrictedAndroidDir(path)) { activity.handlePrimarySAFDialog(path) { if (!it) { @@ -136,7 +136,7 @@ class CreateNewItemDialog(val activity: SimpleActivity, val path: String, val ca } } - path.startsWith(activity.internalStoragePath, true) -> { + isRPlus() || path.startsWith(activity.internalStoragePath, true) -> { if (File(path).createNewFile()) { success(alertDialog) } diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt index 03983da8..8893e599 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt @@ -1,14 +1,14 @@ package com.simplemobiletools.filemanager.pro.fragments +import android.content.ContentResolver import android.content.Context import android.provider.MediaStore.Files import android.provider.MediaStore.Files.FileColumns import android.util.AttributeSet +import androidx.core.os.bundleOf import androidx.recyclerview.widget.GridLayoutManager import com.simplemobiletools.commons.extensions.* -import com.simplemobiletools.commons.helpers.VIEW_TYPE_GRID -import com.simplemobiletools.commons.helpers.VIEW_TYPE_LIST -import com.simplemobiletools.commons.helpers.ensureBackgroundThread +import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.models.FileDirItem import com.simplemobiletools.commons.views.MyGridLayoutManager import com.simplemobiletools.filemanager.pro.R @@ -24,6 +24,8 @@ import kotlinx.android.synthetic.main.recents_fragment.view.* import java.util.* class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet), ItemOperationsListener { + private val RECENTS_LIMIT = 50 + override fun setupFragment(activity: SimpleActivity) { if (this.activity == null) { this.activity = activity @@ -120,17 +122,36 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage FileColumns.SIZE ) - val sortOrder = "${FileColumns.DATE_MODIFIED} DESC LIMIT 50" + val cursor = if (isOreoPlus()) { + val queryArgs = bundleOf( + ContentResolver.QUERY_ARG_LIMIT to RECENTS_LIMIT, + ContentResolver.QUERY_ARG_SORT_COLUMNS to arrayOf(FileColumns.DATE_MODIFIED), + ContentResolver.QUERY_ARG_SORT_DIRECTION to ContentResolver.QUERY_SORT_DIRECTION_DESCENDING + ) + context?.contentResolver?.query(uri, projection, queryArgs, null) + } else { + val sortOrder = "${FileColumns.DATE_MODIFIED} DESC LIMIT $RECENTS_LIMIT" + context?.contentResolver?.query(uri, projection, null, null, sortOrder) + } - context?.queryCursor(uri, projection, sortOrder = sortOrder, showErrors = true) { cursor -> - val path = cursor.getStringValue(FileColumns.DATA) - val name = cursor.getStringValue(FileColumns.DISPLAY_NAME) ?: path.getFilenameFromPath() - val size = cursor.getLongValue(FileColumns.SIZE) - val modified = cursor.getLongValue(FileColumns.DATE_MODIFIED) * 1000 - val fileDirItem = ListItem(path, name, false, 0, size, modified, false) - if ((showHidden || !name.startsWith(".")) && activity?.getDoesFilePathExist(path) == true) { - listItems.add(fileDirItem) + try { + cursor?.use { + if (cursor.moveToFirst()) { + do { + val path = cursor.getStringValue(FileColumns.DATA) + val name = cursor.getStringValue(FileColumns.DISPLAY_NAME) ?: path.getFilenameFromPath() + val size = cursor.getLongValue(FileColumns.SIZE) + val modified = cursor.getLongValue(FileColumns.DATE_MODIFIED) * 1000 + val fileDirItem = ListItem(path, name, false, 0, size, modified, false) + if ((showHidden || !name.startsWith(".")) && activity?.getDoesFilePathExist(path) == true) { + listItems.add(fileDirItem) + } + } while (cursor.moveToNext()) + } } + } catch (e: Exception) { + e.printStackTrace() + activity?.showErrorToast(e) } activity?.runOnUiThread { From b7ef3993f27e511bb67062a66e3e4fb279512944 Mon Sep 17 00:00:00 2001 From: darthpaul Date: Fri, 12 Nov 2021 06:54:59 +0000 Subject: [PATCH 08/18] exclude SD and OTG from SAF restricted directories --- app/build.gradle | 6 ++--- .../filemanager/pro/adapters/ItemsAdapter.kt | 8 ++----- .../pro/dialogs/CreateNewItemDialog.kt | 8 +++---- .../pro/fragments/ItemsFragment.kt | 7 +++++- .../pro/fragments/RecentsFragment.kt | 23 +++++++++---------- build.gradle | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle | 2 +- 8 files changed, 30 insertions(+), 30 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 88cc1fee..898fcb10 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,13 +9,13 @@ if (keystorePropertiesFile.exists()) { } android { - compileSdkVersion 29 + compileSdkVersion 30 buildToolsVersion "29.0.3" defaultConfig { applicationId "com.simplemobiletools.filemanager.pro" minSdkVersion 21 - targetSdkVersion 29 + targetSdkVersion 30 versionCode 108 versionName "6.9.4" multiDexEnabled true @@ -58,7 +58,7 @@ android { } dependencies { - implementation 'com.github.SimpleMobileTools:Simple-Commons:649211e294' + implementation project(":commons") implementation 'com.github.Stericson:RootTools:df729dcb13' implementation 'com.github.Stericson:RootShell:1.6' implementation 'com.alexvasilkov:gesture-views:2.5.2' diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt index 3b1a8493..ab97cdfb 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt @@ -50,12 +50,8 @@ import kotlinx.android.synthetic.main.item_file_dir_list.view.item_name import kotlinx.android.synthetic.main.item_section.view.* import java.io.Closeable import java.io.File -import java.io.FileInputStream -import java.net.URI -import java.net.URLEncoder import java.util.* import java.util.zip.ZipEntry -import java.util.zip.ZipFile import java.util.zip.ZipInputStream import java.util.zip.ZipOutputStream @@ -469,9 +465,9 @@ class ItemsAdapter( CompressAsDialog(activity, firstPath) { val destination = it - activity.handlePrimarySAFDialog(firstPath) { granted -> + activity.handlePrimaryAndroidSAFDialog(firstPath) { granted -> if (!granted) { - return@handlePrimarySAFDialog + return@handlePrimaryAndroidSAFDialog } activity.handleSAFDialog(firstPath) { if (!it) { diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt index e24728c1..fa731fbc 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt @@ -68,10 +68,10 @@ class CreateNewItemDialog(val activity: SimpleActivity, val path: String, val ca } isRPlus() || path.startsWith(activity.internalStoragePath, true) -> { if (activity.isRestrictedAndroidDir(path)) { - activity.handlePrimarySAFDialog(path) { + activity.handlePrimaryAndroidSAFDialog(path) { if (!it) { callback(false) - return@handlePrimarySAFDialog + return@handlePrimaryAndroidSAFDialog } if (activity.createSAFOnlyDirectory(path)) { success(alertDialog) @@ -103,10 +103,10 @@ class CreateNewItemDialog(val activity: SimpleActivity, val path: String, val ca try { when { activity.isRestrictedAndroidDir(path) -> { - activity.handlePrimarySAFDialog(path) { + activity.handlePrimaryAndroidSAFDialog(path) { if (!it) { callback(false) - return@handlePrimarySAFDialog + return@handlePrimaryAndroidSAFDialog } if (activity.createSAFOnlyFile(path)) { success(alertDialog) diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt index 8174e4d0..13e6da3a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt @@ -188,7 +188,12 @@ class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerF val getProperChildCount = context!!.config.getFolderViewType(currentPath) == VIEW_TYPE_LIST if (context.isRestrictedAndroidDir(path)) { - activity?.handlePrimarySAFDialog(path) { + activity?.handlePrimaryAndroidSAFDialog(path) { + if (!it) { + activity?.toast(R.string.no_storage_permissions) + return@handlePrimaryAndroidSAFDialog + } + context.getStorageItemsWithTreeUri(path, context.config.shouldShowHidden, getProperChildCount) { callback(path, getListItemsFromFileDirItems(it)) } diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt index 8893e599..2deea1b6 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt @@ -122,19 +122,18 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage FileColumns.SIZE ) - val cursor = if (isOreoPlus()) { - val queryArgs = bundleOf( - ContentResolver.QUERY_ARG_LIMIT to RECENTS_LIMIT, - ContentResolver.QUERY_ARG_SORT_COLUMNS to arrayOf(FileColumns.DATE_MODIFIED), - ContentResolver.QUERY_ARG_SORT_DIRECTION to ContentResolver.QUERY_SORT_DIRECTION_DESCENDING - ) - context?.contentResolver?.query(uri, projection, queryArgs, null) - } else { - val sortOrder = "${FileColumns.DATE_MODIFIED} DESC LIMIT $RECENTS_LIMIT" - context?.contentResolver?.query(uri, projection, null, null, sortOrder) - } - try { + val cursor = if (isOreoPlus()) { + val queryArgs = bundleOf( + ContentResolver.QUERY_ARG_LIMIT to RECENTS_LIMIT, + ContentResolver.QUERY_ARG_SORT_COLUMNS to arrayOf(FileColumns.DATE_MODIFIED), + ContentResolver.QUERY_ARG_SORT_DIRECTION to ContentResolver.QUERY_SORT_DIRECTION_DESCENDING + ) + context?.contentResolver?.query(uri, projection, queryArgs, null) + } else { + val sortOrder = "${FileColumns.DATE_MODIFIED} DESC LIMIT $RECENTS_LIMIT" + context?.contentResolver?.query(uri, projection, null, null, sortOrder) + } cursor?.use { if (cursor.moveToFirst()) { do { diff --git a/build.gradle b/build.gradle index e0fb0bd8..9b82dbc6 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.5.30' + ext.kotlin_version = '1.5.31' repositories { google() @@ -9,7 +9,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.2.2' + classpath 'com.android.tools.build:gradle:7.0.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7490f4ab..0896a415 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip diff --git a/settings.gradle b/settings.gradle index 772c2522..707304a6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,3 @@ include ':app' include ':commons' -project(":commons").projectDir = new File("/Users/cyberman/StudioProjects/Simple-Commons/commons") +project(":commons").projectDir = new File("/Users/darthpaul/StudioProjects/Simple-Commons/commons") From 627bbb519a1efcbd9eb1fb1e6c2e2961a90c966d Mon Sep 17 00:00:00 2001 From: darthpaul Date: Sun, 14 Nov 2021 00:06:56 +0000 Subject: [PATCH 09/18] cleaning up --- .../filemanager/pro/adapters/ItemsAdapter.kt | 20 ++++---- .../pro/dialogs/CreateNewItemDialog.kt | 47 +++++++++---------- .../filemanager/pro/extensions/Context.kt | 3 +- .../pro/fragments/ItemsFragment.kt | 6 +-- .../pro/fragments/RecentsFragment.kt | 1 - app/src/main/res/menu/cab.xml | 6 +-- app/src/main/res/values-gl/strings.xml | 4 +- 7 files changed, 42 insertions(+), 45 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt index 4308519c..c38f499e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt @@ -330,10 +330,10 @@ class ItemsAdapter( if (activity.getIsPathDirectory(path)) { val shouldShowHidden = activity.config.shouldShowHidden when { - activity.isRestrictedAndroidDir(path) -> { - activity.getStorageItemsWithTreeUri(path, shouldShowHidden, false) { files -> + activity.isRestrictedSAFOnlyRoot(path) -> { + activity.getAndroidSAFFileItems(path, shouldShowHidden, false) { files -> files.forEach { - addFileUris(activity.getPrimaryAndroidSAFUri(it.path).toString(), paths) + addFileUris(activity.getAndroidSAFUri(it.path).toString(), paths) } } } @@ -403,7 +403,7 @@ class ItemsAdapter( if (!isCopyOperation) { files.forEach { sourceFileDir -> val sourcePath = sourceFileDir.path - if (activity.isRestrictedAndroidDir(sourcePath) && activity.getDoesFilePathExist(sourcePath)) { + if (activity.isRestrictedSAFOnlyRoot(sourcePath) && activity.getDoesFilePathExist(sourcePath)) { activity.deleteFile(sourceFileDir, true) { listener?.refreshFragment() activity.runOnUiThread { @@ -521,8 +521,7 @@ class ItemsAdapter( private fun tryDecompressingPaths(sourcePaths: List, callback: (success: Boolean) -> Unit) { sourcePaths.forEach { path -> - val zipInputStream = ZipInputStream(BufferedInputStream(activity.getFileInputStreamSync(path))) - zipInputStream.use { + ZipInputStream(BufferedInputStream(activity.getFileInputStreamSync(path))).use { zipInputStream -> try { val fileDirItems = ArrayList() var entry = zipInputStream.nextEntry @@ -541,6 +540,7 @@ class ItemsAdapter( } } } catch (exception: Exception) { + exception.printStackTrace() activity.showErrorToast(exception) } } @@ -643,8 +643,8 @@ class ItemsAdapter( while (!queue.isEmpty()) { mainFilePath = queue.pop() if (activity.getIsPathDirectory(mainFilePath)) { - if (activity.isRestrictedAndroidDir(mainFilePath)) { - activity.getStorageItemsWithTreeUri(mainFilePath, true) { files -> + if (activity.isRestrictedSAFOnlyRoot(mainFilePath)) { + activity.getAndroidSAFFileItems(mainFilePath, true) { files -> for (file in files) { name = file.path.relativizeWith(base) if (activity.getIsPathDirectory(file.path)) { @@ -884,8 +884,8 @@ class ItemsAdapter( path } - if (activity.isRestrictedAndroidDir(path)) { - itemToLoad = activity.getPrimaryAndroidSAFUri(path) + if (activity.isRestrictedSAFOnlyRoot(path)) { + itemToLoad = activity.getAndroidSAFUri(path) } else if (hasOTGConnected && itemToLoad is String && activity.isPathOnOTG(itemToLoad) && baseConfig.OTGTreeUri.isNotEmpty() && baseConfig.OTGPartition.isNotEmpty()) { itemToLoad = getOTGPublicPath(itemToLoad) } diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt index fa731fbc..d54116c4 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt @@ -51,6 +51,27 @@ class CreateNewItemDialog(val activity: SimpleActivity, val path: String, val ca private fun createDirectory(path: String, alertDialog: AlertDialog, callback: (Boolean) -> Unit) { when { + isRPlus() || path.startsWith(activity.internalStoragePath, true) -> { + if (activity.isRestrictedSAFOnlyRoot(path)) { + activity.handlePrimaryAndroidSAFDialog(path) { + if (!it) { + callback(false) + return@handlePrimaryAndroidSAFDialog + } + if (activity.createAndroidSAFDirectory(path)) { + success(alertDialog) + } else { + val error = String.format(activity.getString(R.string.could_not_create_folder), path) + activity.showErrorToast(error) + callback(false) + } + } + } else { + if (File(path).mkdirs()) { + success(alertDialog) + } + } + } activity.needsStupidWritePermissions(path) -> activity.handleSAFDialog(path) { if (!it) { return@handleSAFDialog @@ -66,27 +87,6 @@ class CreateNewItemDialog(val activity: SimpleActivity, val path: String, val ca documentFile.createDirectory(path.getFilenameFromPath()) success(alertDialog) } - isRPlus() || path.startsWith(activity.internalStoragePath, true) -> { - if (activity.isRestrictedAndroidDir(path)) { - activity.handlePrimaryAndroidSAFDialog(path) { - if (!it) { - callback(false) - return@handlePrimaryAndroidSAFDialog - } - if (activity.createSAFOnlyDirectory(path)) { - success(alertDialog) - } else { - val error = String.format(activity.getString(R.string.could_not_create_folder), path) - activity.showErrorToast(error) - callback(false) - } - } - } else { - if (File(path).mkdirs()) { - success(alertDialog) - } - } - } else -> { RootHelpers(activity).createFileFolder(path, false) { if (it) { @@ -102,13 +102,13 @@ class CreateNewItemDialog(val activity: SimpleActivity, val path: String, val ca private fun createFile(path: String, alertDialog: AlertDialog, callback: (Boolean) -> Unit) { try { when { - activity.isRestrictedAndroidDir(path) -> { + activity.isRestrictedSAFOnlyRoot(path) -> { activity.handlePrimaryAndroidSAFDialog(path) { if (!it) { callback(false) return@handlePrimaryAndroidSAFDialog } - if (activity.createSAFOnlyFile(path)) { + if (activity.createAndroidSAFFile(path)) { success(alertDialog) } else { val error = String.format(activity.getString(R.string.could_not_create_file), path) @@ -141,7 +141,6 @@ class CreateNewItemDialog(val activity: SimpleActivity, val path: String, val ca success(alertDialog) } } - else -> { RootHelpers(activity).createFileFolder(path, true) { if (it) { diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/extensions/Context.kt index 0e30de4a..07b1f5f5 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/extensions/Context.kt @@ -3,9 +3,8 @@ package com.simplemobiletools.filemanager.pro.extensions import android.content.Context import com.simplemobiletools.commons.extensions.isPathOnOTG import com.simplemobiletools.commons.extensions.isPathOnSD -import com.simplemobiletools.commons.extensions.otgPath -import com.simplemobiletools.commons.extensions.sdCardPath import com.simplemobiletools.filemanager.pro.helpers.Config val Context.config: Config get() = Config.newInstance(applicationContext) + fun Context.isPathOnRoot(path: String) = !(path.startsWith(config.internalStoragePath) || isPathOnOTG(path) || (isPathOnSD(path))) diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt index 784841d3..56856166 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt @@ -187,15 +187,15 @@ class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerF val isSortingBySize = context!!.config.getFolderSorting(currentPath) and SORT_BY_SIZE != 0 val getProperChildCount = context!!.config.getFolderViewType(currentPath) == VIEW_TYPE_LIST - if (context.isRestrictedAndroidDir(path)) { + if (context.isRestrictedSAFOnlyRoot(path)) { activity?.handlePrimaryAndroidSAFDialog(path) { if (!it) { activity?.toast(R.string.no_storage_permissions) return@handlePrimaryAndroidSAFDialog } - context.getStorageItemsWithTreeUri(path, context.config.shouldShowHidden, getProperChildCount) { - callback(path, getListItemsFromFileDirItems(it)) + context.getAndroidSAFFileItems(path, context.config.shouldShowHidden, getProperChildCount) { fileItems -> + callback(path, getListItemsFromFileDirItems(fileItems)) } } } else { diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt index 39541e45..a2f0c66e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt @@ -149,7 +149,6 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage } } } catch (e: Exception) { - e.printStackTrace() activity?.showErrorToast(e) } diff --git a/app/src/main/res/menu/cab.xml b/app/src/main/res/menu/cab.xml index b179b77b..7dfbb6db 100644 --- a/app/src/main/res/menu/cab.xml +++ b/app/src/main/res/menu/cab.xml @@ -13,12 +13,12 @@ app:showAsAction="always"/> - Simple File Manager Pro - Manage files easily & fast + Simple File Manager Pro - Manage files easily & fast - Quick file management with no ads. Browse files easily, securely & fast + Quick file management with no ads. Browse files easily, securely & fast Un xestor de ficheiros rápido e lixeiro para uso diario. Ofrece unha funcionalidade de busca útil e podes personalizar o cartafol de inicio e seleccionar os cartafoles favoritos para un acceso rápido. From 781870e73260db031ecfb25b2436cd50689aa598 Mon Sep 17 00:00:00 2001 From: darthpaul Date: Sun, 14 Nov 2021 22:19:28 +0000 Subject: [PATCH 10/18] method renaming and reformat --- .../filemanager/pro/adapters/ItemsAdapter.kt | 4 +- .../pro/dialogs/CreateNewItemDialog.kt | 8 +-- .../pro/fragments/ItemsFragment.kt | 66 ++++++++----------- .../pro/fragments/RecentsFragment.kt | 5 +- 4 files changed, 37 insertions(+), 46 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt index c38f499e..69907b87 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt @@ -465,9 +465,9 @@ class ItemsAdapter( CompressAsDialog(activity, firstPath) { val destination = it - activity.handlePrimaryAndroidSAFDialog(firstPath) { granted -> + activity.handleAndroidSAFDialog(firstPath) { granted -> if (!granted) { - return@handlePrimaryAndroidSAFDialog + return@handleAndroidSAFDialog } activity.handleSAFDialog(firstPath) { if (!it) { diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt index d54116c4..86fb1370 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/dialogs/CreateNewItemDialog.kt @@ -53,10 +53,10 @@ class CreateNewItemDialog(val activity: SimpleActivity, val path: String, val ca when { isRPlus() || path.startsWith(activity.internalStoragePath, true) -> { if (activity.isRestrictedSAFOnlyRoot(path)) { - activity.handlePrimaryAndroidSAFDialog(path) { + activity.handleAndroidSAFDialog(path) { if (!it) { callback(false) - return@handlePrimaryAndroidSAFDialog + return@handleAndroidSAFDialog } if (activity.createAndroidSAFDirectory(path)) { success(alertDialog) @@ -103,10 +103,10 @@ class CreateNewItemDialog(val activity: SimpleActivity, val path: String, val ca try { when { activity.isRestrictedSAFOnlyRoot(path) -> { - activity.handlePrimaryAndroidSAFDialog(path) { + activity.handleAndroidSAFDialog(path) { if (!it) { callback(false) - return@handlePrimaryAndroidSAFDialog + return@handleAndroidSAFDialog } if (activity.createAndroidSAFFile(path)) { success(alertDialog) diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt index 56856166..9917bf05 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt @@ -162,7 +162,18 @@ class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerF ensureBackgroundThread { if (activity?.isDestroyed == false && activity?.isFinishing == false) { val config = context!!.config - if (context!!.isPathOnOTG(path) && config.OTGTreeUri.isNotEmpty()) { + if (context.isRestrictedSAFOnlyRoot(path)) { + activity?.handleAndroidSAFDialog(path) { + if (!it) { + activity?.toast(R.string.no_storage_permissions) + return@handleAndroidSAFDialog + } + val getProperChildCount = context!!.config.getFolderViewType(currentPath) == VIEW_TYPE_LIST + context.getAndroidSAFFileItems(path, context.config.shouldShowHidden, getProperChildCount) { fileItems -> + callback(path, getListItemsFromFileDirItems(fileItems)) + } + } + } else if (context!!.isPathOnOTG(path) && config.OTGTreeUri.isNotEmpty()) { val getProperFileSize = context!!.config.getFolderSorting(currentPath) and SORT_BY_SIZE != 0 context!!.getOTGItems(path, config.shouldShowHidden, getProperFileSize) { callback(path, getListItemsFromFileDirItems(it)) @@ -178,52 +189,33 @@ class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerF private fun getRegularItemsOf(path: String, callback: (originalPath: String, items: ArrayList) -> Unit) { val items = ArrayList() - - if (context == null) { + val files = File(path).listFiles()?.filterNotNull() + if (context == null || files == null) { callback(path, items) return } val isSortingBySize = context!!.config.getFolderSorting(currentPath) and SORT_BY_SIZE != 0 val getProperChildCount = context!!.config.getFolderViewType(currentPath) == VIEW_TYPE_LIST + val lastModifieds = context!!.getFolderLastModifieds(path) - if (context.isRestrictedSAFOnlyRoot(path)) { - activity?.handlePrimaryAndroidSAFDialog(path) { - if (!it) { - activity?.toast(R.string.no_storage_permissions) - return@handlePrimaryAndroidSAFDialog - } - - context.getAndroidSAFFileItems(path, context.config.shouldShowHidden, getProperChildCount) { fileItems -> - callback(path, getListItemsFromFileDirItems(fileItems)) - } + for (file in files) { + val fileDirItem = getFileDirItemFromFile(file, isSortingBySize, lastModifieds, false) + if (fileDirItem != null) { + items.add(fileDirItem) } - } else { - val files = File(path).listFiles()?.filterNotNull() - if (files == null) { - callback(path, items) - return - } - val lastModifieds = context!!.getFolderLastModifieds(path) + } - for (file in files) { - val fileDirItem = getFileDirItemFromFile(file, isSortingBySize, lastModifieds, false) - if (fileDirItem != null) { - items.add(fileDirItem) - } - } + // send out the initial item list asap, get proper child count asynchronously as it can be slow + callback(path, items) - // send out the initial item list asap, get proper child count asynchronously as it can be slow - callback(path, items) - - if (getProperChildCount) { - items.filter { it.mIsDirectory }.forEach { - if (context != null) { - val childrenCount = it.getDirectChildrenCount(activity as BaseSimpleActivity, showHidden) - if (childrenCount != 0) { - activity?.runOnUiThread { - getRecyclerAdapter()?.updateChildCount(it.mPath, childrenCount) - } + if (getProperChildCount) { + items.filter { it.mIsDirectory }.forEach { + if (context != null) { + val childrenCount = it.getDirectChildrenCount(activity as BaseSimpleActivity, showHidden) + if (childrenCount != 0) { + activity?.runOnUiThread { + getRecyclerAdapter()?.updateChildCount(it.mPath, childrenCount) } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt index a2f0c66e..49438aa6 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/RecentsFragment.kt @@ -123,7 +123,7 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage ) try { - val cursor = if (isOreoPlus()) { + if (isOreoPlus()) { val queryArgs = bundleOf( ContentResolver.QUERY_ARG_LIMIT to RECENTS_LIMIT, ContentResolver.QUERY_ARG_SORT_COLUMNS to arrayOf(FileColumns.DATE_MODIFIED), @@ -133,8 +133,7 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage } else { val sortOrder = "${FileColumns.DATE_MODIFIED} DESC LIMIT $RECENTS_LIMIT" context?.contentResolver?.query(uri, projection, null, null, sortOrder) - } - cursor?.use { + }?.use { cursor -> if (cursor.moveToFirst()) { do { val path = cursor.getStringValue(FileColumns.DATA) From c695fd0955361c86409bff4130cf35c65fc14298 Mon Sep 17 00:00:00 2001 From: darthpaul Date: Sun, 14 Nov 2021 22:33:51 +0000 Subject: [PATCH 11/18] update commons --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 80dfb569..63dfec45 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -58,7 +58,7 @@ android { } dependencies { - implementation project(":commons") + implementation 'com.github.SimpleMobileTools:Simple-Commons:c7f376f7cd' implementation 'com.github.Stericson:RootTools:df729dcb13' implementation 'com.github.Stericson:RootShell:1.6' implementation 'com.alexvasilkov:gesture-views:2.5.2' From d92af2f97dda08c7110ab389e8c70807e7743283 Mon Sep 17 00:00:00 2001 From: darthpaul Date: Sun, 14 Nov 2021 23:00:12 +0000 Subject: [PATCH 12/18] ensure decompression is in background thread --- .../filemanager/pro/adapters/ItemsAdapter.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt index 69907b87..e5aaf931 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/adapters/ItemsAdapter.kt @@ -505,15 +505,17 @@ class ItemsAdapter( } val paths = getSelectedFileDirItems().asSequence().map { it.path }.filter { it.isZipFile() }.toList() - tryDecompressingPaths(paths) { - if (it) { - activity.toast(R.string.decompression_successful) + ensureBackgroundThread { + tryDecompressingPaths(paths) { success -> activity.runOnUiThread { - listener?.refreshFragment() - finishActMode() + if (success) { + activity.toast(R.string.decompression_successful) + listener?.refreshFragment() + finishActMode() + } else { + activity.toast(R.string.decompressing_failed) + } } - } else { - activity.toast(R.string.decompressing_failed) } } } @@ -540,7 +542,6 @@ class ItemsAdapter( } } } catch (exception: Exception) { - exception.printStackTrace() activity.showErrorToast(exception) } } @@ -589,7 +590,6 @@ class ItemsAdapter( } callback(true) } catch (e: Exception) { - e.printStackTrace() activity.showErrorToast(e) callback(false) } From 77ec965e40103d8dbad2e41bf25544a6a8bbbf37 Mon Sep 17 00:00:00 2001 From: darthpaul Date: Mon, 15 Nov 2021 09:04:02 +0000 Subject: [PATCH 13/18] update settings.gradle --- settings.gradle | 2 -- 1 file changed, 2 deletions(-) diff --git a/settings.gradle b/settings.gradle index 707304a6..e7b4def4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1 @@ include ':app' -include ':commons' -project(":commons").projectDir = new File("/Users/darthpaul/StudioProjects/Simple-Commons/commons") From dc55b35dae1756bbdc7a892ceeb75ee6e015dfa8 Mon Sep 17 00:00:00 2001 From: darthpaul Date: Tue, 16 Nov 2021 22:18:51 +0000 Subject: [PATCH 14/18] remove printing exeception stacktrace --- .../simplemobiletools/filemanager/pro/activities/MainActivity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/MainActivity.kt index b21a76f7..0e8ab0bb 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/MainActivity.kt @@ -320,7 +320,6 @@ class MainActivity : SimpleActivity() { intent.data = Uri.parse("package:$packageName") startActivityForResult(intent, MANAGE_STORAGE_RC) } catch (e: Exception) { - e.printStackTrace() val intent = Intent() intent.action = Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION startActivityForResult(intent, MANAGE_STORAGE_RC) From 2b0b6e1079206886e12093446adfa3e3ad14fc03 Mon Sep 17 00:00:00 2001 From: Tibor Kaputa Date: Sun, 21 Nov 2021 22:13:21 +0100 Subject: [PATCH 15/18] Update build.gradle --- app/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 63dfec45..e14f7c00 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,7 +10,6 @@ if (keystorePropertiesFile.exists()) { android { compileSdkVersion 30 - buildToolsVersion "29.0.3" defaultConfig { applicationId "com.simplemobiletools.filemanager.pro" From 3c8a67349aeb190b93bb85bc944770bd43123cf8 Mon Sep 17 00:00:00 2001 From: Tibor Kaputa Date: Sun, 21 Nov 2021 22:58:20 +0100 Subject: [PATCH 16/18] Update build.gradle --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index e14f7c00..71592065 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -57,7 +57,7 @@ android { } dependencies { - implementation 'com.github.SimpleMobileTools:Simple-Commons:c7f376f7cd' + implementation 'com.github.SimpleMobileTools:Simple-Commons:4e6eeb901f' implementation 'com.github.Stericson:RootTools:df729dcb13' implementation 'com.github.Stericson:RootShell:1.6' implementation 'com.alexvasilkov:gesture-views:2.5.2' From 3294bc26a77bed10862a76d24411ea81772b65ad Mon Sep 17 00:00:00 2001 From: Tibor Kaputa Date: Sun, 21 Nov 2021 22:58:45 +0100 Subject: [PATCH 17/18] show a confirmation dialog before redirecting to the device settings --- .../pro/activities/MainActivity.kt | 43 +++++++++++++------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/MainActivity.kt index 00439b06..9ce9de22 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/activities/MainActivity.kt @@ -1,5 +1,6 @@ package com.simplemobiletools.filemanager.pro.activities +import android.annotation.SuppressLint import android.app.Activity import android.app.SearchManager import android.content.ClipData @@ -16,9 +17,10 @@ import android.provider.Settings import android.view.Menu import android.view.MenuItem import androidx.appcompat.widget.SearchView -import androidx.core.app.ActivityCompat import androidx.core.view.MenuItemCompat import androidx.viewpager.widget.ViewPager +import com.simplemobiletools.commons.dialogs.ConfirmationAdvancedDialog +import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.dialogs.RadioGroupDialog import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.* @@ -46,7 +48,6 @@ import kotlinx.android.synthetic.main.items_fragment.view.* import kotlinx.android.synthetic.main.recents_fragment.* import kotlinx.android.synthetic.main.storage_fragment.* import java.io.File -import java.lang.Exception import java.util.* class MainActivity : SimpleActivity() { @@ -306,23 +307,31 @@ class MainActivity : SimpleActivity() { } } + @SuppressLint("InlinedApi") private fun handleStoragePermission(callback: (granted: Boolean) -> Unit) { actionOnPermission = null if (hasStoragePermission()) { callback(true) } else { if (isRPlus()) { - isAskingPermissions = true - actionOnPermission = callback - try { - val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) - intent.addCategory("android.intent.category.DEFAULT") - intent.data = Uri.parse("package:$packageName") - startActivityForResult(intent, MANAGE_STORAGE_RC) - } catch (e: Exception) { - val intent = Intent() - intent.action = Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION - startActivityForResult(intent, MANAGE_STORAGE_RC) + ConfirmationAdvancedDialog(this, "", R.string.access_storage_prompt, R.string.ok, 0) { success -> + if (success ) { + isAskingPermissions = true + actionOnPermission = callback + try { + val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) + intent.addCategory("android.intent.category.DEFAULT") + intent.data = Uri.parse("package:$packageName") + startActivityForResult(intent, MANAGE_STORAGE_RC) + } catch (e: Exception) { + showErrorToast(e) + val intent = Intent() + intent.action = Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION + startActivityForResult(intent, MANAGE_STORAGE_RC) + } + } else { + finish() + } } } else { handlePermission(PERMISSION_WRITE_STORAGE, callback) @@ -330,10 +339,16 @@ class MainActivity : SimpleActivity() { } } + @SuppressLint("NewApi") private fun hasStoragePermission(): Boolean { - return if (isRPlus()) Environment.isExternalStorageManager() else hasPermission(PERMISSION_WRITE_STORAGE) + return if (isRPlus()) { + Environment.isExternalStorageManager() + } else { + hasPermission(PERMISSION_WRITE_STORAGE) + } } + @SuppressLint("NewApi") override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { super.onActivityResult(requestCode, resultCode, resultData) isAskingPermissions = false From de00b6929994e5a399262733f07c22370f6196ee Mon Sep 17 00:00:00 2001 From: Tibor Kaputa Date: Sun, 21 Nov 2021 23:18:24 +0100 Subject: [PATCH 18/18] do not fill out the breadcrumbs before handling permissions --- .../filemanager/pro/fragments/ItemsFragment.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt index 9917bf05..3b31bcdc 100644 --- a/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/filemanager/pro/fragments/ItemsFragment.kt @@ -23,10 +23,10 @@ import com.simplemobiletools.filemanager.pro.helpers.MAX_COLUMN_COUNT import com.simplemobiletools.filemanager.pro.helpers.RootHelpers import com.simplemobiletools.filemanager.pro.interfaces.ItemOperationsListener import com.simplemobiletools.filemanager.pro.models.ListItem +import kotlinx.android.synthetic.main.items_fragment.view.* import java.io.File import java.util.* import kotlin.collections.ArrayList -import kotlinx.android.synthetic.main.items_fragment.view.* class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet), ItemOperationsListener, Breadcrumbs.BreadcrumbsListener { @@ -58,13 +58,18 @@ class ItemsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerF initDrawables() } - breadcrumbs.updateColor(textColor) items_fastscroller.updateBubbleColors() + + if (currentPath != "") { + breadcrumbs.updateColor(textColor) + } } override fun setupFontSize() { getRecyclerAdapter()?.updateFontSizes() - breadcrumbs.updateFontSize(context!!.getTextSize()) + if (currentPath != "") { + breadcrumbs.updateFontSize(context!!.getTextSize()) + } } override fun setupDateTimeFormat() {