forked from hardcoresushi/DroidFS
Improving handling of SD cards errors
This commit is contained in:
parent
3795f8790f
commit
0b509c2f98
@ -66,7 +66,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
|
||||
override fun onPictureTaken(result: PictureResult) {
|
||||
take_photo_button.onPhotoTaken()
|
||||
val inputStream = ByteArrayInputStream(result.data)
|
||||
if (gocryptfsVolume.importFile(inputStream, PathUtils.path_join(outputDirectory, fileName))){
|
||||
if (gocryptfsVolume.importFile(inputStream, PathUtils.pathJoin(outputDirectory, fileName))){
|
||||
Toast.makeText(applicationContext, getString(R.string.picture_save_success, fileName), Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(applicationContext)
|
||||
|
@ -78,7 +78,7 @@ class ChangePasswordActivity : VolumeActionActivity() {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
||||
if (data?.data != null) {
|
||||
if (PathUtils.isTreeUriOnPrimaryStorage(data.data)){
|
||||
if (PathUtils.isTreeUriOnPrimaryStorage(data.data!!)){
|
||||
val path = PathUtils.getFullPathFromTreeUri(data.data, this)
|
||||
if (path != null){
|
||||
edit_volume_path.setText(path)
|
||||
|
@ -45,7 +45,7 @@ class CreateActivity : VolumeActionActivity() {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
||||
if (data?.data != null) {
|
||||
if (PathUtils.isTreeUriOnPrimaryStorage(data.data)){
|
||||
if (PathUtils.isTreeUriOnPrimaryStorage(data.data!!)){
|
||||
val path = PathUtils.getFullPathFromTreeUri(data.data, this)
|
||||
if (path != null){
|
||||
edit_volume_path.setText(path)
|
||||
|
@ -100,7 +100,6 @@ class OpenActivity : VolumeActionActivity() {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
||||
if (data?.data != null) {
|
||||
if (PathUtils.isTreeUriOnPrimaryStorage(data.data)){
|
||||
val path = PathUtils.getFullPathFromTreeUri(data.data, this)
|
||||
if (path != null){
|
||||
edit_volume_path.setText(path)
|
||||
@ -111,13 +110,6 @@ class OpenActivity : VolumeActionActivity() {
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.open_on_sdcard_warning)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -129,19 +121,37 @@ class OpenActivity : VolumeActionActivity() {
|
||||
Toast.makeText(this, R.string.enter_volume_path, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
val rootCipherDirFile = File(rootCipherDir)
|
||||
if (!GocryptfsVolume.isGocryptfsVolume(rootCipherDirFile)){
|
||||
if (!rootCipherDirFile.canRead()) {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.open_cant_read_error)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
} else if (!GocryptfsVolume.isGocryptfsVolume(rootCipherDirFile)){
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.error_not_a_volume)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
} else if (!rootCipherDirFile.canWrite()) {
|
||||
if ((intent.action == Intent.ACTION_SEND || intent.action == Intent.ACTION_SEND_MULTIPLE) && intent.extras != null) { //import via android share menu
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.open_cant_write_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
} else {
|
||||
val dialog = ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.open_cant_write_warning)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.ok) { _, _ -> openVolume() }
|
||||
.show()
|
||||
if (PathUtils.isPathOnExternalStorage(rootCipherDir, this)){
|
||||
dialog.setMessage(R.string.open_on_sdcard_warning)
|
||||
} else {
|
||||
dialog.setMessage(R.string.open_cant_write_warning)
|
||||
}
|
||||
dialog.show()
|
||||
}
|
||||
} else {
|
||||
openVolume()
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package sushi.hardcore.droidfs.explorers
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
@ -35,9 +37,11 @@ import sushi.hardcore.droidfs.file_viewers.VideoPlayer
|
||||
import sushi.hardcore.droidfs.provider.RestrictedFileProvider
|
||||
import sushi.hardcore.droidfs.util.ExternalProvider
|
||||
import sushi.hardcore.droidfs.util.GocryptfsVolume
|
||||
import sushi.hardcore.droidfs.util.LoadingTask
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
|
||||
open class BaseExplorerActivity : BaseActivity() {
|
||||
private lateinit var sortOrderEntries: Array<String>
|
||||
@ -235,7 +239,7 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
if (folder_name.isEmpty()) {
|
||||
Toast.makeText(this, R.string.error_filename_empty, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
if (!gocryptfsVolume.mkdir(PathUtils.path_join(currentDirectoryPath, folder_name))) {
|
||||
if (!gocryptfsVolume.mkdir(PathUtils.pathJoin(currentDirectoryPath, folder_name))) {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.error_mkdir)
|
||||
@ -291,13 +295,13 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
.setView(dialogEditTextView)
|
||||
.setTitle(R.string.enter_new_name)
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
handler.sendMessage(Message().apply { obj = checkPathOverwrite(PathUtils.path_join(PathUtils.getParentPath(path), dialogEditText.text.toString()), isDirectory) })
|
||||
handler.sendMessage(Message().apply { obj = checkPathOverwrite(PathUtils.pathJoin(PathUtils.getParentPath(path), dialogEditText.text.toString()), isDirectory) })
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { _, _ -> handler.sendMessage(Message().apply { obj = null }) }
|
||||
.create()
|
||||
dialogEditText.setOnEditorActionListener { _, _, _ ->
|
||||
dialog.dismiss()
|
||||
handler.sendMessage(Message().apply { obj = checkPathOverwrite(PathUtils.path_join(PathUtils.getParentPath(path), dialogEditText.text.toString()), isDirectory) })
|
||||
handler.sendMessage(Message().apply { obj = checkPathOverwrite(PathUtils.pathJoin(PathUtils.getParentPath(path), dialogEditText.text.toString()), isDirectory) })
|
||||
true
|
||||
}
|
||||
dialog.setOnCancelListener { handler.sendMessage(Message().apply { obj = null }) }
|
||||
@ -317,11 +321,57 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
return outputPath
|
||||
}
|
||||
|
||||
protected fun importFilesFromUris(uris: List<Uri>, task: LoadingTask, callback: (DialogInterface.OnClickListener)? = null): Boolean {
|
||||
var success = false
|
||||
for (uri in uris) {
|
||||
val fileName = PathUtils.getFilenameFromURI(task.activity, uri)
|
||||
if (fileName == null){
|
||||
task.stopTask {
|
||||
ColoredAlertDialogBuilder(task.activity)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.error_retrieving_filename, uri))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
success = false
|
||||
break
|
||||
} else {
|
||||
val dstPath = checkPathOverwrite(PathUtils.pathJoin(currentDirectoryPath, fileName), false)
|
||||
if (dstPath == null){
|
||||
break
|
||||
} else {
|
||||
var message: String? = null
|
||||
try {
|
||||
success = gocryptfsVolume.importFile(task.activity, uri, dstPath)
|
||||
} catch (e: FileNotFoundException){
|
||||
message = if (e.message != null){
|
||||
e.message!!+"\n"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
if (!success || message != null) {
|
||||
task.stopTask {
|
||||
ColoredAlertDialogBuilder(task.activity)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage((message ?: "")+getString(R.string.import_failed, uri))
|
||||
.setCancelable(callback == null)
|
||||
.setPositiveButton(R.string.ok, callback)
|
||||
.show()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
protected fun rename(old_name: String, new_name: String){
|
||||
if (new_name.isEmpty()) {
|
||||
Toast.makeText(this, R.string.error_filename_empty, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
if (!gocryptfsVolume.rename(PathUtils.path_join(currentDirectoryPath, old_name), PathUtils.path_join(currentDirectoryPath, new_name))) {
|
||||
if (!gocryptfsVolume.rename(PathUtils.pathJoin(currentDirectoryPath, old_name), PathUtils.pathJoin(currentDirectoryPath, new_name))) {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.rename_failed, old_name))
|
||||
@ -400,7 +450,7 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
}
|
||||
R.id.external_open -> {
|
||||
if (usf_open){
|
||||
openWithExternalApp(PathUtils.path_join(currentDirectoryPath, explorerElements[explorerAdapter.selectedItems[0]].name))
|
||||
openWithExternalApp(PathUtils.pathJoin(currentDirectoryPath, explorerElements[explorerAdapter.selectedItems[0]].name))
|
||||
unselectAll()
|
||||
}
|
||||
true
|
||||
|
@ -47,7 +47,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
if (fileName.isEmpty()) {
|
||||
Toast.makeText(this, R.string.error_filename_empty, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
checkPathOverwrite(PathUtils.path_join(currentDirectoryPath, fileName), false)?.let {
|
||||
checkPathOverwrite(PathUtils.pathJoin(currentDirectoryPath, fileName), false)?.let {
|
||||
val handleID = gocryptfsVolume.openWriteMode(it)
|
||||
if (handleID == -1) {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
@ -153,28 +153,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
uris.add(singleUri)
|
||||
}
|
||||
Looper.prepare()
|
||||
var success = false
|
||||
for (uri in uris) {
|
||||
val dstPath = checkPathOverwrite(PathUtils.path_join(currentDirectoryPath, PathUtils.getFilenameFromURI(activity, uri)), false)
|
||||
if (dstPath == null){
|
||||
break
|
||||
} else {
|
||||
contentResolver.openInputStream(uri)?.let {
|
||||
success = gocryptfsVolume.importFile(it, dstPath)
|
||||
}
|
||||
if (!success) {
|
||||
stopTask {
|
||||
ColoredAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.import_failed, uri))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
if (importFilesFromUris(uris, this)) {
|
||||
stopTask {
|
||||
ColoredAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.success_import)
|
||||
@ -185,7 +164,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
.setPositiveButton(R.string.yes) { _, _ ->
|
||||
object : LoadingTask(activity, R.string.loading_msg_wipe){
|
||||
override fun doTask(activity: AppCompatActivity) {
|
||||
success = true
|
||||
var success = true
|
||||
for (uri in uris) {
|
||||
val errorMsg = Wiper.wipe(activity, uri)
|
||||
if (errorMsg != null) {
|
||||
@ -232,7 +211,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
var failedItem: String? = null
|
||||
for (i in explorerAdapter.selectedItems) {
|
||||
val element = explorerAdapter.getItem(i)
|
||||
val fullPath = PathUtils.path_join(currentDirectoryPath, element.name)
|
||||
val fullPath = PathUtils.pathJoin(currentDirectoryPath, element.name)
|
||||
failedItem = if (element.isDirectory) {
|
||||
recursiveExportDirectory(fullPath, treeDocumentFile)
|
||||
} else {
|
||||
@ -283,7 +262,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
failedItem = if (types[i] == 0) { //directory
|
||||
recursiveImportDirectoryFromOtherVolume(remoteGocryptfsVolume, paths[i], currentDirectoryPath)
|
||||
} else {
|
||||
safeImportFileFromOtherVolume(remoteGocryptfsVolume, paths[i], PathUtils.path_join(currentDirectoryPath, File(paths[i]).name))
|
||||
safeImportFileFromOtherVolume(remoteGocryptfsVolume, paths[i], PathUtils.pathJoin(currentDirectoryPath, File(paths[i]).name))
|
||||
}
|
||||
if (failedItem != null) {
|
||||
break
|
||||
@ -291,7 +270,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
failedItem = safeImportFileFromOtherVolume(remoteGocryptfsVolume, path, PathUtils.path_join(currentDirectoryPath, File(path).name))
|
||||
failedItem = safeImportFileFromOtherVolume(remoteGocryptfsVolume, path, PathUtils.pathJoin(currentDirectoryPath, File(path).name))
|
||||
}
|
||||
if (failedItem == null) {
|
||||
stopTask {
|
||||
@ -386,7 +365,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
var failedItem: String? = null
|
||||
Looper.prepare()
|
||||
for (element in itemsToProcess) {
|
||||
val dstPath = checkPathOverwrite(PathUtils.path_join(currentDirectoryPath, element.name), element.isDirectory)
|
||||
val dstPath = checkPathOverwrite(PathUtils.pathJoin(currentDirectoryPath, element.name), element.isDirectory)
|
||||
failedItem = if (dstPath == null){
|
||||
""
|
||||
} else {
|
||||
@ -547,7 +526,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
}
|
||||
}
|
||||
for (e in mappedElements) {
|
||||
val dstPath = checkPathOverwrite(PathUtils.path_join(dstDirectoryPath, PathUtils.getRelativePath(srcDirectoryPath, e.fullPath)), e.isDirectory)
|
||||
val dstPath = checkPathOverwrite(PathUtils.pathJoin(dstDirectoryPath, PathUtils.getRelativePath(srcDirectoryPath, e.fullPath)), e.isDirectory)
|
||||
if (dstPath == null){
|
||||
return ""
|
||||
} else {
|
||||
@ -581,7 +560,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
|
||||
private fun moveElements(elements: List<ExplorerElement>, dstDirectoryPath: String): String? {
|
||||
for (element in elements){
|
||||
val dstPath = checkPathOverwrite(PathUtils.path_join(dstDirectoryPath, element.name), element.isDirectory)
|
||||
val dstPath = checkPathOverwrite(PathUtils.pathJoin(dstDirectoryPath, element.name), element.isDirectory)
|
||||
if (dstPath == null){
|
||||
return ""
|
||||
} else {
|
||||
@ -636,7 +615,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
|
||||
private fun recursiveImportDirectoryFromOtherVolume(remote_gocryptfsVolume: GocryptfsVolume, remote_directory_path: String, outputPath: String): String? {
|
||||
val mappedElements = remote_gocryptfsVolume.recursiveMapFiles(remote_directory_path)
|
||||
val dstDirectoryPath = checkPathOverwrite(PathUtils.path_join(outputPath, File(remote_directory_path).name), true)
|
||||
val dstDirectoryPath = checkPathOverwrite(PathUtils.pathJoin(outputPath, File(remote_directory_path).name), true)
|
||||
if (dstDirectoryPath == null){
|
||||
return ""
|
||||
} else {
|
||||
@ -646,7 +625,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
}
|
||||
}
|
||||
for (e in mappedElements) {
|
||||
val dstPath = checkPathOverwrite(PathUtils.path_join(dstDirectoryPath, PathUtils.getRelativePath(remote_directory_path, e.fullPath)), e.isDirectory)
|
||||
val dstPath = checkPathOverwrite(PathUtils.pathJoin(dstDirectoryPath, PathUtils.getRelativePath(remote_directory_path, e.fullPath)), e.isDirectory)
|
||||
if (dstPath == null){
|
||||
return ""
|
||||
} else {
|
||||
@ -682,7 +661,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
treeDocumentFile.createDirectory(File(plain_directory_path).name)?.let {childTree ->
|
||||
val explorerElements = gocryptfsVolume.listDir(plain_directory_path)
|
||||
for (e in explorerElements) {
|
||||
val fullPath = PathUtils.path_join(plain_directory_path, e.name)
|
||||
val fullPath = PathUtils.pathJoin(plain_directory_path, e.name)
|
||||
if (e.isDirectory) {
|
||||
val failedItem = recursiveExportDirectory(fullPath, childTree)
|
||||
failedItem?.let { return it }
|
||||
@ -700,7 +679,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
private fun recursiveRemoveDirectory(plain_directory_path: String): String? {
|
||||
val explorerElements = gocryptfsVolume.listDir(plain_directory_path)
|
||||
for (e in explorerElements) {
|
||||
val fullPath = PathUtils.path_join(plain_directory_path, e.name)
|
||||
val fullPath = PathUtils.pathJoin(plain_directory_path, e.name)
|
||||
if (e.isDirectory) {
|
||||
val result = recursiveRemoveDirectory(fullPath)
|
||||
result?.let { return it }
|
||||
@ -721,7 +700,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
var failedItem: String? = null
|
||||
for (i in explorerAdapter.selectedItems) {
|
||||
val element = explorerAdapter.getItem(i)
|
||||
val fullPath = PathUtils.path_join(currentDirectoryPath, element.name)
|
||||
val fullPath = PathUtils.pathJoin(currentDirectoryPath, element.name)
|
||||
if (element.isDirectory) {
|
||||
val result = recursiveRemoveDirectory(fullPath)
|
||||
result?.let{ failedItem = it }
|
||||
|
@ -1,5 +1,6 @@
|
||||
package sushi.hardcore.droidfs.explorers
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Looper
|
||||
@ -9,7 +10,6 @@ import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.util.LoadingTask
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
|
||||
class ExplorerActivityDrop : BaseExplorerActivity() {
|
||||
@ -36,42 +36,30 @@ class ExplorerActivityDrop : BaseExplorerActivity() {
|
||||
val alertDialog = ColoredAlertDialogBuilder(activity)
|
||||
alertDialog.setCancelable(false)
|
||||
alertDialog.setPositiveButton(R.string.ok) { _, _ -> finish() }
|
||||
var errorMsg: String? = null
|
||||
val errorMsg: String?
|
||||
val extras = intent.extras
|
||||
if (extras != null && extras.containsKey(Intent.EXTRA_STREAM)){
|
||||
Looper.prepare()
|
||||
if (intent.action == Intent.ACTION_SEND) {
|
||||
when (intent.action) {
|
||||
Intent.ACTION_SEND -> {
|
||||
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
|
||||
errorMsg = if (uri == null){
|
||||
getString(R.string.share_intent_parsing_failed)
|
||||
} else {
|
||||
val outputPath = checkPathOverwrite(PathUtils.path_join(currentDirectoryPath, PathUtils.getFilenameFromURI(activity, uri)), false)
|
||||
if (outputPath == null) {
|
||||
""
|
||||
} else {
|
||||
if (gocryptfsVolume.importFile(activity, uri, outputPath)) null else getString(R.string.import_failed, uri)
|
||||
if (importFilesFromUris(listOf(uri), this){ _, _ -> finish() }) null else ""
|
||||
}
|
||||
}
|
||||
} else if (intent.action == Intent.ACTION_SEND_MULTIPLE) {
|
||||
Intent.ACTION_SEND_MULTIPLE -> {
|
||||
val uris = intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)
|
||||
if (uris != null){
|
||||
for (uri in uris) {
|
||||
val outputPath = checkPathOverwrite(PathUtils.path_join(currentDirectoryPath, PathUtils.getFilenameFromURI(activity, uri)), false)
|
||||
if (outputPath == null){
|
||||
errorMsg = ""
|
||||
break
|
||||
errorMsg = if (uris != null){
|
||||
if (importFilesFromUris(uris, this){ _, _ -> finish() }) null else ""
|
||||
} else {
|
||||
if (!gocryptfsVolume.importFile(activity, uri, outputPath)) {
|
||||
errorMsg = getString(R.string.import_failed, uri)
|
||||
break
|
||||
getString(R.string.share_intent_parsing_failed)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
else -> {
|
||||
errorMsg = getString(R.string.share_intent_parsing_failed)
|
||||
}
|
||||
} else {
|
||||
errorMsg = getString(R.string.share_intent_parsing_failed)
|
||||
}
|
||||
} else {
|
||||
errorMsg = getString(R.string.share_intent_parsing_failed)
|
||||
|
@ -22,7 +22,7 @@ class ExplorerActivityPick : BaseExplorerActivity() {
|
||||
explorerAdapter.onItemClick(position)
|
||||
if (explorerAdapter.selectedItems.isEmpty()) {
|
||||
if (!wasSelecting) {
|
||||
val fullPath = PathUtils.path_join(currentDirectoryPath, explorerElements[position].name)
|
||||
val fullPath = PathUtils.pathJoin(currentDirectoryPath, explorerElements[position].name)
|
||||
when {
|
||||
explorerElements[position].isDirectory -> {
|
||||
setCurrentPath(fullPath)
|
||||
@ -61,7 +61,7 @@ class ExplorerActivityPick : BaseExplorerActivity() {
|
||||
val types = ArrayList<Int>()
|
||||
for (i in explorerAdapter.selectedItems) {
|
||||
val e = explorerElements[i]
|
||||
paths.add(PathUtils.path_join(currentDirectoryPath, e.name))
|
||||
paths.add(PathUtils.pathJoin(currentDirectoryPath, e.name))
|
||||
types.add(e.elementType.toInt())
|
||||
}
|
||||
resultIntent.putStringArrayListExtra("paths", paths)
|
||||
|
@ -5,7 +5,7 @@ import java.util.*
|
||||
|
||||
class ExplorerElement(val name: String, val elementType: Short, var size: Long, mtime: Long, parentPath: String) {
|
||||
val mTime = Date((mtime * 1000).toString().toLong())
|
||||
val fullPath: String = PathUtils.path_join(parentPath, name)
|
||||
val fullPath: String = PathUtils.pathJoin(parentPath, name)
|
||||
|
||||
val isDirectory: Boolean
|
||||
get() = elementType.toInt() == 0
|
||||
|
@ -7,7 +7,7 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
|
||||
abstract class LoadingTask(private val activity: AppCompatActivity, private val loadingMessageResId: Int) {
|
||||
abstract class LoadingTask(val activity: AppCompatActivity, loadingMessageResId: Int) {
|
||||
private val dialogLoadingView = activity.layoutInflater.inflate(R.layout.dialog_loading, null)
|
||||
private val dialogLoading: AlertDialog = ColoredAlertDialogBuilder(activity)
|
||||
.setView(dialogLoadingView)
|
||||
@ -31,7 +31,7 @@ abstract class LoadingTask(private val activity: AppCompatActivity, private val
|
||||
activity.runOnUiThread { doFinally(activity) }
|
||||
}.start()
|
||||
}
|
||||
protected fun stopTask(onUiThread: (() -> Unit)?){
|
||||
fun stopTask(onUiThread: (() -> Unit)?){
|
||||
isStopped = true
|
||||
dialogLoading.dismiss()
|
||||
onUiThread?.let {
|
||||
|
@ -1,157 +0,0 @@
|
||||
package sushi.hardcore.droidfs.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.OpenableColumns;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
public class PathUtils {
|
||||
|
||||
public static String getParentPath(String path){
|
||||
if (path.endsWith("/")){
|
||||
String a = path.substring(0, path.length()-2);
|
||||
if (a.contains("/")){
|
||||
return a.substring(0, a.lastIndexOf("/"));
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
if (path.contains("/")){
|
||||
return path.substring(0, path.lastIndexOf("/"));
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String path_join(String... strings){
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (String element : strings){
|
||||
if (!element.isEmpty()){
|
||||
if (!element.endsWith("/")){
|
||||
element += "/";
|
||||
}
|
||||
result.append(element);
|
||||
}
|
||||
}
|
||||
return result.substring(0, result.length()-1);
|
||||
}
|
||||
|
||||
public static String getRelativePath(String parentPath, String childPath){
|
||||
return childPath.substring(parentPath.length()+1);
|
||||
}
|
||||
|
||||
public static String getFilenameFromURI(Context context, Uri uri){
|
||||
String result = null;
|
||||
if (uri.getScheme().equals("content")){
|
||||
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
|
||||
if (cursor != null){
|
||||
try {
|
||||
if (cursor.moveToFirst()){
|
||||
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result == null){
|
||||
result = uri.getPath();
|
||||
int cut = result.lastIndexOf('/');
|
||||
if (cut != -1){
|
||||
result = result.substring(cut + 1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static final String[] units = new String[]{"B", "kB", "MB", "GB", "TB"};
|
||||
public static String formatSize(long size){
|
||||
if (size <= 0){
|
||||
return "0 B";
|
||||
}
|
||||
int digitGroups = (int)(Math.log10(size)/Math.log10(1024));
|
||||
return new DecimalFormat("#,##0.#").format(size/Math.pow(1024, digitGroups))+" "+units[digitGroups];
|
||||
}
|
||||
|
||||
public static Boolean isTreeUriOnPrimaryStorage(Uri treeUri){
|
||||
String volumeId = getVolumeIdFromTreeUri(treeUri);
|
||||
if (volumeId != null) {
|
||||
return volumeId.equals(PRIMARY_VOLUME_NAME) || volumeId.equals("home") || volumeId.equals("downloads");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String PRIMARY_VOLUME_NAME = "primary";
|
||||
@Nullable
|
||||
public static String getFullPathFromTreeUri(@Nullable Uri treeUri, Context context) {
|
||||
if (treeUri == null) return null;
|
||||
if ("content".equalsIgnoreCase(treeUri.getScheme())) {
|
||||
String volumePath = getVolumePath(getVolumeIdFromTreeUri(treeUri),context);
|
||||
if (volumePath == null) return null;
|
||||
if (volumePath.endsWith(File.separator))
|
||||
volumePath = volumePath.substring(0, volumePath.length() - 1);
|
||||
String documentPath = getDocumentPathFromTreeUri(treeUri);
|
||||
if (documentPath.endsWith(File.separator))
|
||||
documentPath = documentPath.substring(0, documentPath.length() - 1);
|
||||
if (documentPath.length() > 0) {
|
||||
return path_join(volumePath, documentPath);
|
||||
}
|
||||
else return volumePath;
|
||||
} else if ("file".equalsIgnoreCase(treeUri.getScheme())) {
|
||||
return treeUri.getPath();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getVolumePath(final String volumeId, Context context) {
|
||||
try {
|
||||
StorageManager mStorageManager =
|
||||
(StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
|
||||
Class<?> storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
|
||||
Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
|
||||
Method getUuid = storageVolumeClazz.getMethod("getUuid");
|
||||
Method getPath = storageVolumeClazz.getMethod("getPath");
|
||||
Method isPrimary = storageVolumeClazz.getMethod("isPrimary");
|
||||
Object result = getVolumeList.invoke(mStorageManager);
|
||||
|
||||
final int length = Array.getLength(result);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Object storageVolumeElement = Array.get(result, i);
|
||||
String uuid = (String) getUuid.invoke(storageVolumeElement);
|
||||
Boolean primary = (Boolean) isPrimary.invoke(storageVolumeElement);
|
||||
if (primary && PRIMARY_VOLUME_NAME.equals(volumeId))
|
||||
return (String) getPath.invoke(storageVolumeElement);
|
||||
if (uuid != null && uuid.equals(volumeId))
|
||||
return (String) getPath.invoke(storageVolumeElement);
|
||||
}
|
||||
return null;
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getVolumeIdFromTreeUri(final Uri treeUri) {
|
||||
final String docId = DocumentsContract.getTreeDocumentId(treeUri);
|
||||
final String[] split = docId.split(":");
|
||||
if (split.length > 0) return split[0];
|
||||
else return null;
|
||||
}
|
||||
|
||||
private static String getDocumentPathFromTreeUri(final Uri treeUri) {
|
||||
final String docId = DocumentsContract.getTreeDocumentId(treeUri);
|
||||
final String[] split = docId.split(":");
|
||||
if ((split.length >= 2) && (split[1] != null)) return split[1];
|
||||
else return File.separator;
|
||||
}
|
||||
}
|
163
app/src/main/java/sushi/hardcore/droidfs/util/PathUtils.kt
Normal file
163
app/src/main/java/sushi/hardcore/droidfs/util/PathUtils.kt
Normal file
@ -0,0 +1,163 @@
|
||||
package sushi.hardcore.droidfs.util
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.storage.StorageManager
|
||||
import android.provider.DocumentsContract
|
||||
import android.provider.OpenableColumns
|
||||
import androidx.core.content.ContextCompat
|
||||
import java.io.File
|
||||
import java.text.DecimalFormat
|
||||
import kotlin.math.log10
|
||||
import kotlin.math.pow
|
||||
|
||||
object PathUtils {
|
||||
fun getParentPath(path: String): String {
|
||||
return if (path.endsWith("/")) {
|
||||
val a = path.substring(0, path.length - 2)
|
||||
if (a.contains("/")) {
|
||||
a.substring(0, a.lastIndexOf("/"))
|
||||
} else {
|
||||
""
|
||||
}
|
||||
} else {
|
||||
if (path.contains("/")) {
|
||||
path.substring(0, path.lastIndexOf("/"))
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun pathJoin(vararg strings: String): String {
|
||||
val result = StringBuilder()
|
||||
for (element in strings) {
|
||||
if (element.isNotEmpty()) {
|
||||
result.append(element)
|
||||
if (!element.endsWith("/")) {
|
||||
result.append("/")
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.substring(0, result.length - 1)
|
||||
}
|
||||
|
||||
fun getRelativePath(parentPath: String, childPath: String): String {
|
||||
return childPath.substring(parentPath.length + 1)
|
||||
}
|
||||
|
||||
fun getFilenameFromURI(context: Context, uri: Uri): String? {
|
||||
var result: String? = null
|
||||
if (uri.scheme == "content") {
|
||||
context.contentResolver.query(uri, null, null, null, null)?.use { cursor ->
|
||||
if (cursor.moveToFirst()) {
|
||||
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result == null) {
|
||||
result = uri.path
|
||||
result?.let {
|
||||
val cut = it.lastIndexOf('/')
|
||||
if (cut != -1) {
|
||||
result = it.substring(cut + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private val units = arrayOf("B", "kB", "MB", "GB", "TB")
|
||||
fun formatSize(size: Long): String {
|
||||
if (size <= 0) {
|
||||
return "0 B"
|
||||
}
|
||||
val digitGroups = (log10(size.toDouble()) / log10(1024.0)).toInt()
|
||||
return DecimalFormat("#,##0.#").format(size / 1024.0.pow(digitGroups.toDouble())
|
||||
) + " " + units[digitGroups]
|
||||
}
|
||||
|
||||
fun isTreeUriOnPrimaryStorage(treeUri: Uri): Boolean {
|
||||
val volumeId = getVolumeIdFromTreeUri(treeUri)
|
||||
return if (volumeId != null) {
|
||||
volumeId == PRIMARY_VOLUME_NAME || volumeId == "home" || volumeId == "downloads"
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun getExternalStoragePath(context: Context): List<String> {
|
||||
val externalPaths: MutableList<String> = ArrayList()
|
||||
ContextCompat.getExternalFilesDirs(context, null).forEach {
|
||||
val rootPath = it.path.substring(0, it.path.indexOf(pathJoin("Android/data/", context.packageName, "files")))
|
||||
if (!rootPath.endsWith("/0/")){ //not primary storage
|
||||
externalPaths.add(rootPath)
|
||||
}
|
||||
}
|
||||
return externalPaths
|
||||
}
|
||||
|
||||
fun isPathOnExternalStorage(path: String, context: Context): Boolean {
|
||||
getExternalStoragePath(context).forEach {
|
||||
if (path.startsWith(it)){
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private const val PRIMARY_VOLUME_NAME = "primary"
|
||||
fun getFullPathFromTreeUri(treeUri: Uri?, context: Context): String? {
|
||||
if (treeUri == null) return null
|
||||
if ("content".equals(treeUri.scheme, ignoreCase = true)) {
|
||||
val vId = getVolumeIdFromTreeUri(treeUri)
|
||||
var volumePath = getVolumePath(vId, context) ?: return null
|
||||
if (volumePath.endsWith(File.separator))
|
||||
volumePath = volumePath.substring(0, volumePath.length - 1)
|
||||
var documentPath = getDocumentPathFromTreeUri(treeUri)
|
||||
if (documentPath!!.endsWith(File.separator))
|
||||
documentPath = documentPath.substring(0, documentPath.length - 1)
|
||||
return if (documentPath.isNotEmpty()) {
|
||||
pathJoin(volumePath, documentPath)
|
||||
} else volumePath
|
||||
} else if ("file".equals(treeUri.scheme, ignoreCase = true)) {
|
||||
return treeUri.path
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getVolumePath(volumeId: String?, context: Context): String? {
|
||||
return try {
|
||||
val mStorageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
|
||||
val storageVolumeClazz = Class.forName("android.os.storage.StorageVolume")
|
||||
val getVolumeList = mStorageManager.javaClass.getMethod("getVolumeList")
|
||||
val getUuid = storageVolumeClazz.getMethod("getUuid")
|
||||
val getPath = storageVolumeClazz.getMethod("getPath")
|
||||
val isPrimary = storageVolumeClazz.getMethod("isPrimary")
|
||||
val result = getVolumeList.invoke(mStorageManager)
|
||||
val length = java.lang.reflect.Array.getLength(result!!)
|
||||
for (i in 0 until length) {
|
||||
val storageVolumeElement = java.lang.reflect.Array.get(result, i)
|
||||
val uuid = getUuid.invoke(storageVolumeElement)
|
||||
val primary = isPrimary.invoke(storageVolumeElement) as Boolean
|
||||
if (primary && PRIMARY_VOLUME_NAME == volumeId) return getPath.invoke(storageVolumeElement) as String
|
||||
if (uuid == volumeId) return getPath.invoke(storageVolumeElement) as String
|
||||
}
|
||||
null
|
||||
} catch (ex: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getVolumeIdFromTreeUri(treeUri: Uri): String? {
|
||||
val docId = DocumentsContract.getTreeDocumentId(treeUri)
|
||||
val split = docId.split(":").toTypedArray()
|
||||
return if (split.isNotEmpty()) split[0] else null
|
||||
}
|
||||
|
||||
private fun getDocumentPathFromTreeUri(treeUri: Uri): String? {
|
||||
val docId = DocumentsContract.getTreeDocumentId(treeUri)
|
||||
val split: Array<String?> = docId.split(":").toTypedArray()
|
||||
return if (split.size >= 2 && split[1] != null) split[1] else File.separator
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@
|
||||
<string name="export_failed">Export of %s failed.</string>
|
||||
<string name="success_export">Export successful !</string>
|
||||
<string name="success_export_msg">The selected files have been successfully exported.</string>
|
||||
<string name="remove_failed">Deletion of %s failed</string>
|
||||
<string name="remove_failed">Deletion of %s failed.</string>
|
||||
<string name="passwords_mismatch">Passwords don\'t match</string>
|
||||
<string name="dir_not_empty">The selected directory isn\'t empty</string>
|
||||
<string name="success_volume_create">Volume successfully created !</string>
|
||||
@ -164,8 +164,10 @@
|
||||
<string name="path_from_uri_null_error_msg">Failed to retrieve the selected path.</string>
|
||||
<string name="create_cant_write_error_msg">DroidFS doesn\'t have write access to this path. Please try another location.</string>
|
||||
<string name="create_on_sdcard_error_msg">DroidFS can\'t write on removable SD cards, please select a path on internal storage.</string>
|
||||
<string name="open_on_sdcard_warning">DroidFS can\'t write on removable SD cards. You will only have read-only access to the volumes therein.</string>
|
||||
<string name="open_cant_write_warning">DroidFS doesn\'t have write access to this path. You will only have read-only access to this volume.</string>
|
||||
<string name="open_on_sdcard_warning">DroidFS can\'t write on removable SD cards. Opening volume with read-only access.</string>
|
||||
<string name="open_cant_write_warning">DroidFS doesn\'t have write access to this path. Opening volume with read-only access.</string>
|
||||
<string name="open_cant_write_error_msg">DroidFS doesn\'t have write access to this path. Please try another volume.</string>
|
||||
<string name="open_cant_read_error">DroidFS doesn\'t have read access to this path. You can try to move the volume to a readable location.</string>
|
||||
<string name="change_pwd_cant_write_error_msg">DroidFS doesn\'t have write access to this path. You can try to move the volume to a writable location.</string>
|
||||
<string name="change_pwd_on_sdcard_error_msg">DroidFS can\'t write on removable SD cards, please move the volume to internal storage.</string>
|
||||
<string name="slideshow_stopped">Slideshow stopped</string>
|
||||
@ -182,4 +184,5 @@
|
||||
<string name="no_more_images">No more images found.</string>
|
||||
<string name="usf_read_doc">You should read it carefully before enabling any of these options.</string>
|
||||
<string name="usf_doc">Unsafe features documentation</string>
|
||||
<string name="error_retrieving_filename">Unable to retrieve file name for URI: %s</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user