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) {
|
override fun onPictureTaken(result: PictureResult) {
|
||||||
take_photo_button.onPhotoTaken()
|
take_photo_button.onPhotoTaken()
|
||||||
val inputStream = ByteArrayInputStream(result.data)
|
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()
|
Toast.makeText(applicationContext, getString(R.string.picture_save_success, fileName), Toast.LENGTH_SHORT).show()
|
||||||
} else {
|
} else {
|
||||||
ColoredAlertDialogBuilder(applicationContext)
|
ColoredAlertDialogBuilder(applicationContext)
|
||||||
|
@ -78,7 +78,7 @@ class ChangePasswordActivity : VolumeActionActivity() {
|
|||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
||||||
if (data?.data != null) {
|
if (data?.data != null) {
|
||||||
if (PathUtils.isTreeUriOnPrimaryStorage(data.data)){
|
if (PathUtils.isTreeUriOnPrimaryStorage(data.data!!)){
|
||||||
val path = PathUtils.getFullPathFromTreeUri(data.data, this)
|
val path = PathUtils.getFullPathFromTreeUri(data.data, this)
|
||||||
if (path != null){
|
if (path != null){
|
||||||
edit_volume_path.setText(path)
|
edit_volume_path.setText(path)
|
||||||
|
@ -45,7 +45,7 @@ class CreateActivity : VolumeActionActivity() {
|
|||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
||||||
if (data?.data != null) {
|
if (data?.data != null) {
|
||||||
if (PathUtils.isTreeUriOnPrimaryStorage(data.data)){
|
if (PathUtils.isTreeUriOnPrimaryStorage(data.data!!)){
|
||||||
val path = PathUtils.getFullPathFromTreeUri(data.data, this)
|
val path = PathUtils.getFullPathFromTreeUri(data.data, this)
|
||||||
if (path != null){
|
if (path != null){
|
||||||
edit_volume_path.setText(path)
|
edit_volume_path.setText(path)
|
||||||
|
@ -100,21 +100,13 @@ class OpenActivity : VolumeActionActivity() {
|
|||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
||||||
if (data?.data != null) {
|
if (data?.data != null) {
|
||||||
if (PathUtils.isTreeUriOnPrimaryStorage(data.data)){
|
val path = PathUtils.getFullPathFromTreeUri(data.data, this)
|
||||||
val path = PathUtils.getFullPathFromTreeUri(data.data, this)
|
if (path != null){
|
||||||
if (path != null){
|
edit_volume_path.setText(path)
|
||||||
edit_volume_path.setText(path)
|
|
||||||
} else {
|
|
||||||
ColoredAlertDialogBuilder(this)
|
|
||||||
.setTitle(R.string.error)
|
|
||||||
.setMessage(R.string.path_from_uri_null_error_msg)
|
|
||||||
.setPositiveButton(R.string.ok, null)
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ColoredAlertDialogBuilder(this)
|
ColoredAlertDialogBuilder(this)
|
||||||
.setTitle(R.string.warning)
|
.setTitle(R.string.error)
|
||||||
.setMessage(R.string.open_on_sdcard_warning)
|
.setMessage(R.string.path_from_uri_null_error_msg)
|
||||||
.setPositiveButton(R.string.ok, null)
|
.setPositiveButton(R.string.ok, null)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
@ -129,19 +121,37 @@ class OpenActivity : VolumeActionActivity() {
|
|||||||
Toast.makeText(this, R.string.enter_volume_path, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.enter_volume_path, Toast.LENGTH_SHORT).show()
|
||||||
} else {
|
} else {
|
||||||
val rootCipherDirFile = File(rootCipherDir)
|
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)
|
ColoredAlertDialogBuilder(this)
|
||||||
.setTitle(R.string.error)
|
.setTitle(R.string.error)
|
||||||
.setMessage(R.string.error_not_a_volume)
|
.setMessage(R.string.error_not_a_volume)
|
||||||
.setPositiveButton(R.string.ok, null)
|
.setPositiveButton(R.string.ok, null)
|
||||||
.show()
|
.show()
|
||||||
} else if (!rootCipherDirFile.canWrite()) {
|
} else if (!rootCipherDirFile.canWrite()) {
|
||||||
ColoredAlertDialogBuilder(this)
|
if ((intent.action == Intent.ACTION_SEND || intent.action == Intent.ACTION_SEND_MULTIPLE) && intent.extras != null) { //import via android share menu
|
||||||
.setTitle(R.string.warning)
|
ColoredAlertDialogBuilder(this)
|
||||||
.setMessage(R.string.open_cant_write_warning)
|
.setTitle(R.string.error)
|
||||||
.setCancelable(false)
|
.setMessage(R.string.open_cant_write_error_msg)
|
||||||
.setPositiveButton(R.string.ok) { _, _ -> openVolume() }
|
.setPositiveButton(R.string.ok, null)
|
||||||
.show()
|
.show()
|
||||||
|
} else {
|
||||||
|
val dialog = ColoredAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.warning)
|
||||||
|
.setCancelable(false)
|
||||||
|
.setPositiveButton(R.string.ok) { _, _ -> openVolume() }
|
||||||
|
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 {
|
} else {
|
||||||
openVolume()
|
openVolume()
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package sushi.hardcore.droidfs.explorers
|
package sushi.hardcore.droidfs.explorers
|
||||||
|
|
||||||
|
import android.content.DialogInterface
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
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.provider.RestrictedFileProvider
|
||||||
import sushi.hardcore.droidfs.util.ExternalProvider
|
import sushi.hardcore.droidfs.util.ExternalProvider
|
||||||
import sushi.hardcore.droidfs.util.GocryptfsVolume
|
import sushi.hardcore.droidfs.util.GocryptfsVolume
|
||||||
|
import sushi.hardcore.droidfs.util.LoadingTask
|
||||||
import sushi.hardcore.droidfs.util.PathUtils
|
import sushi.hardcore.droidfs.util.PathUtils
|
||||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.FileNotFoundException
|
||||||
|
|
||||||
open class BaseExplorerActivity : BaseActivity() {
|
open class BaseExplorerActivity : BaseActivity() {
|
||||||
private lateinit var sortOrderEntries: Array<String>
|
private lateinit var sortOrderEntries: Array<String>
|
||||||
@ -235,7 +239,7 @@ open class BaseExplorerActivity : BaseActivity() {
|
|||||||
if (folder_name.isEmpty()) {
|
if (folder_name.isEmpty()) {
|
||||||
Toast.makeText(this, R.string.error_filename_empty, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.error_filename_empty, Toast.LENGTH_SHORT).show()
|
||||||
} else {
|
} else {
|
||||||
if (!gocryptfsVolume.mkdir(PathUtils.path_join(currentDirectoryPath, folder_name))) {
|
if (!gocryptfsVolume.mkdir(PathUtils.pathJoin(currentDirectoryPath, folder_name))) {
|
||||||
ColoredAlertDialogBuilder(this)
|
ColoredAlertDialogBuilder(this)
|
||||||
.setTitle(R.string.error)
|
.setTitle(R.string.error)
|
||||||
.setMessage(R.string.error_mkdir)
|
.setMessage(R.string.error_mkdir)
|
||||||
@ -291,13 +295,13 @@ open class BaseExplorerActivity : BaseActivity() {
|
|||||||
.setView(dialogEditTextView)
|
.setView(dialogEditTextView)
|
||||||
.setTitle(R.string.enter_new_name)
|
.setTitle(R.string.enter_new_name)
|
||||||
.setPositiveButton(R.string.ok) { _, _ ->
|
.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 }) }
|
.setNegativeButton(R.string.cancel) { _, _ -> handler.sendMessage(Message().apply { obj = null }) }
|
||||||
.create()
|
.create()
|
||||||
dialogEditText.setOnEditorActionListener { _, _, _ ->
|
dialogEditText.setOnEditorActionListener { _, _, _ ->
|
||||||
dialog.dismiss()
|
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
|
true
|
||||||
}
|
}
|
||||||
dialog.setOnCancelListener { handler.sendMessage(Message().apply { obj = null }) }
|
dialog.setOnCancelListener { handler.sendMessage(Message().apply { obj = null }) }
|
||||||
@ -317,11 +321,57 @@ open class BaseExplorerActivity : BaseActivity() {
|
|||||||
return outputPath
|
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){
|
protected fun rename(old_name: String, new_name: String){
|
||||||
if (new_name.isEmpty()) {
|
if (new_name.isEmpty()) {
|
||||||
Toast.makeText(this, R.string.error_filename_empty, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.error_filename_empty, Toast.LENGTH_SHORT).show()
|
||||||
} else {
|
} 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)
|
ColoredAlertDialogBuilder(this)
|
||||||
.setTitle(R.string.error)
|
.setTitle(R.string.error)
|
||||||
.setMessage(getString(R.string.rename_failed, old_name))
|
.setMessage(getString(R.string.rename_failed, old_name))
|
||||||
@ -400,7 +450,7 @@ open class BaseExplorerActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
R.id.external_open -> {
|
R.id.external_open -> {
|
||||||
if (usf_open){
|
if (usf_open){
|
||||||
openWithExternalApp(PathUtils.path_join(currentDirectoryPath, explorerElements[explorerAdapter.selectedItems[0]].name))
|
openWithExternalApp(PathUtils.pathJoin(currentDirectoryPath, explorerElements[explorerAdapter.selectedItems[0]].name))
|
||||||
unselectAll()
|
unselectAll()
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -47,7 +47,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
if (fileName.isEmpty()) {
|
if (fileName.isEmpty()) {
|
||||||
Toast.makeText(this, R.string.error_filename_empty, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.error_filename_empty, Toast.LENGTH_SHORT).show()
|
||||||
} else {
|
} else {
|
||||||
checkPathOverwrite(PathUtils.path_join(currentDirectoryPath, fileName), false)?.let {
|
checkPathOverwrite(PathUtils.pathJoin(currentDirectoryPath, fileName), false)?.let {
|
||||||
val handleID = gocryptfsVolume.openWriteMode(it)
|
val handleID = gocryptfsVolume.openWriteMode(it)
|
||||||
if (handleID == -1) {
|
if (handleID == -1) {
|
||||||
ColoredAlertDialogBuilder(this)
|
ColoredAlertDialogBuilder(this)
|
||||||
@ -153,28 +153,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
uris.add(singleUri)
|
uris.add(singleUri)
|
||||||
}
|
}
|
||||||
Looper.prepare()
|
Looper.prepare()
|
||||||
var success = false
|
if (importFilesFromUris(uris, this)) {
|
||||||
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) {
|
|
||||||
stopTask {
|
stopTask {
|
||||||
ColoredAlertDialogBuilder(activity)
|
ColoredAlertDialogBuilder(activity)
|
||||||
.setTitle(R.string.success_import)
|
.setTitle(R.string.success_import)
|
||||||
@ -185,7 +164,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
.setPositiveButton(R.string.yes) { _, _ ->
|
.setPositiveButton(R.string.yes) { _, _ ->
|
||||||
object : LoadingTask(activity, R.string.loading_msg_wipe){
|
object : LoadingTask(activity, R.string.loading_msg_wipe){
|
||||||
override fun doTask(activity: AppCompatActivity) {
|
override fun doTask(activity: AppCompatActivity) {
|
||||||
success = true
|
var success = true
|
||||||
for (uri in uris) {
|
for (uri in uris) {
|
||||||
val errorMsg = Wiper.wipe(activity, uri)
|
val errorMsg = Wiper.wipe(activity, uri)
|
||||||
if (errorMsg != null) {
|
if (errorMsg != null) {
|
||||||
@ -232,7 +211,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
var failedItem: String? = null
|
var failedItem: String? = null
|
||||||
for (i in explorerAdapter.selectedItems) {
|
for (i in explorerAdapter.selectedItems) {
|
||||||
val element = explorerAdapter.getItem(i)
|
val element = explorerAdapter.getItem(i)
|
||||||
val fullPath = PathUtils.path_join(currentDirectoryPath, element.name)
|
val fullPath = PathUtils.pathJoin(currentDirectoryPath, element.name)
|
||||||
failedItem = if (element.isDirectory) {
|
failedItem = if (element.isDirectory) {
|
||||||
recursiveExportDirectory(fullPath, treeDocumentFile)
|
recursiveExportDirectory(fullPath, treeDocumentFile)
|
||||||
} else {
|
} else {
|
||||||
@ -283,7 +262,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
failedItem = if (types[i] == 0) { //directory
|
failedItem = if (types[i] == 0) { //directory
|
||||||
recursiveImportDirectoryFromOtherVolume(remoteGocryptfsVolume, paths[i], currentDirectoryPath)
|
recursiveImportDirectoryFromOtherVolume(remoteGocryptfsVolume, paths[i], currentDirectoryPath)
|
||||||
} else {
|
} 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) {
|
if (failedItem != null) {
|
||||||
break
|
break
|
||||||
@ -291,7 +270,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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) {
|
if (failedItem == null) {
|
||||||
stopTask {
|
stopTask {
|
||||||
@ -386,7 +365,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
var failedItem: String? = null
|
var failedItem: String? = null
|
||||||
Looper.prepare()
|
Looper.prepare()
|
||||||
for (element in itemsToProcess) {
|
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){
|
failedItem = if (dstPath == null){
|
||||||
""
|
""
|
||||||
} else {
|
} else {
|
||||||
@ -547,7 +526,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (e in mappedElements) {
|
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){
|
if (dstPath == null){
|
||||||
return ""
|
return ""
|
||||||
} else {
|
} else {
|
||||||
@ -581,7 +560,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
|
|
||||||
private fun moveElements(elements: List<ExplorerElement>, dstDirectoryPath: String): String? {
|
private fun moveElements(elements: List<ExplorerElement>, dstDirectoryPath: String): String? {
|
||||||
for (element in elements){
|
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){
|
if (dstPath == null){
|
||||||
return ""
|
return ""
|
||||||
} else {
|
} else {
|
||||||
@ -636,7 +615,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
|
|
||||||
private fun recursiveImportDirectoryFromOtherVolume(remote_gocryptfsVolume: GocryptfsVolume, remote_directory_path: String, outputPath: String): String? {
|
private fun recursiveImportDirectoryFromOtherVolume(remote_gocryptfsVolume: GocryptfsVolume, remote_directory_path: String, outputPath: String): String? {
|
||||||
val mappedElements = remote_gocryptfsVolume.recursiveMapFiles(remote_directory_path)
|
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){
|
if (dstDirectoryPath == null){
|
||||||
return ""
|
return ""
|
||||||
} else {
|
} else {
|
||||||
@ -646,7 +625,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (e in mappedElements) {
|
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){
|
if (dstPath == null){
|
||||||
return ""
|
return ""
|
||||||
} else {
|
} else {
|
||||||
@ -682,7 +661,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
treeDocumentFile.createDirectory(File(plain_directory_path).name)?.let {childTree ->
|
treeDocumentFile.createDirectory(File(plain_directory_path).name)?.let {childTree ->
|
||||||
val explorerElements = gocryptfsVolume.listDir(plain_directory_path)
|
val explorerElements = gocryptfsVolume.listDir(plain_directory_path)
|
||||||
for (e in explorerElements) {
|
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) {
|
if (e.isDirectory) {
|
||||||
val failedItem = recursiveExportDirectory(fullPath, childTree)
|
val failedItem = recursiveExportDirectory(fullPath, childTree)
|
||||||
failedItem?.let { return it }
|
failedItem?.let { return it }
|
||||||
@ -700,7 +679,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
private fun recursiveRemoveDirectory(plain_directory_path: String): String? {
|
private fun recursiveRemoveDirectory(plain_directory_path: String): String? {
|
||||||
val explorerElements = gocryptfsVolume.listDir(plain_directory_path)
|
val explorerElements = gocryptfsVolume.listDir(plain_directory_path)
|
||||||
for (e in explorerElements) {
|
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) {
|
if (e.isDirectory) {
|
||||||
val result = recursiveRemoveDirectory(fullPath)
|
val result = recursiveRemoveDirectory(fullPath)
|
||||||
result?.let { return it }
|
result?.let { return it }
|
||||||
@ -721,7 +700,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
var failedItem: String? = null
|
var failedItem: String? = null
|
||||||
for (i in explorerAdapter.selectedItems) {
|
for (i in explorerAdapter.selectedItems) {
|
||||||
val element = explorerAdapter.getItem(i)
|
val element = explorerAdapter.getItem(i)
|
||||||
val fullPath = PathUtils.path_join(currentDirectoryPath, element.name)
|
val fullPath = PathUtils.pathJoin(currentDirectoryPath, element.name)
|
||||||
if (element.isDirectory) {
|
if (element.isDirectory) {
|
||||||
val result = recursiveRemoveDirectory(fullPath)
|
val result = recursiveRemoveDirectory(fullPath)
|
||||||
result?.let{ failedItem = it }
|
result?.let{ failedItem = it }
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package sushi.hardcore.droidfs.explorers
|
package sushi.hardcore.droidfs.explorers
|
||||||
|
|
||||||
|
import android.content.DialogInterface
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
@ -9,7 +10,6 @@ import android.view.View
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import sushi.hardcore.droidfs.R
|
import sushi.hardcore.droidfs.R
|
||||||
import sushi.hardcore.droidfs.util.LoadingTask
|
import sushi.hardcore.droidfs.util.LoadingTask
|
||||||
import sushi.hardcore.droidfs.util.PathUtils
|
|
||||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||||
|
|
||||||
class ExplorerActivityDrop : BaseExplorerActivity() {
|
class ExplorerActivityDrop : BaseExplorerActivity() {
|
||||||
@ -36,42 +36,30 @@ class ExplorerActivityDrop : BaseExplorerActivity() {
|
|||||||
val alertDialog = ColoredAlertDialogBuilder(activity)
|
val alertDialog = ColoredAlertDialogBuilder(activity)
|
||||||
alertDialog.setCancelable(false)
|
alertDialog.setCancelable(false)
|
||||||
alertDialog.setPositiveButton(R.string.ok) { _, _ -> finish() }
|
alertDialog.setPositiveButton(R.string.ok) { _, _ -> finish() }
|
||||||
var errorMsg: String? = null
|
val errorMsg: String?
|
||||||
val extras = intent.extras
|
val extras = intent.extras
|
||||||
if (extras != null && extras.containsKey(Intent.EXTRA_STREAM)){
|
if (extras != null && extras.containsKey(Intent.EXTRA_STREAM)){
|
||||||
Looper.prepare()
|
Looper.prepare()
|
||||||
if (intent.action == Intent.ACTION_SEND) {
|
when (intent.action) {
|
||||||
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
|
Intent.ACTION_SEND -> {
|
||||||
errorMsg = if (uri == null){
|
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
|
||||||
getString(R.string.share_intent_parsing_failed)
|
errorMsg = if (uri == null){
|
||||||
} else {
|
getString(R.string.share_intent_parsing_failed)
|
||||||
val outputPath = checkPathOverwrite(PathUtils.path_join(currentDirectoryPath, PathUtils.getFilenameFromURI(activity, uri)), false)
|
|
||||||
if (outputPath == null) {
|
|
||||||
""
|
|
||||||
} else {
|
} 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)
|
val uris = intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)
|
||||||
if (uris != null){
|
errorMsg = if (uris != null){
|
||||||
for (uri in uris) {
|
if (importFilesFromUris(uris, this){ _, _ -> finish() }) null else ""
|
||||||
val outputPath = checkPathOverwrite(PathUtils.path_join(currentDirectoryPath, PathUtils.getFilenameFromURI(activity, uri)), false)
|
} else {
|
||||||
if (outputPath == null){
|
getString(R.string.share_intent_parsing_failed)
|
||||||
errorMsg = ""
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
if (!gocryptfsVolume.importFile(activity, uri, outputPath)) {
|
|
||||||
errorMsg = getString(R.string.import_failed, uri)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
errorMsg = getString(R.string.share_intent_parsing_failed)
|
errorMsg = getString(R.string.share_intent_parsing_failed)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
errorMsg = getString(R.string.share_intent_parsing_failed)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errorMsg = getString(R.string.share_intent_parsing_failed)
|
errorMsg = getString(R.string.share_intent_parsing_failed)
|
||||||
|
@ -22,7 +22,7 @@ class ExplorerActivityPick : BaseExplorerActivity() {
|
|||||||
explorerAdapter.onItemClick(position)
|
explorerAdapter.onItemClick(position)
|
||||||
if (explorerAdapter.selectedItems.isEmpty()) {
|
if (explorerAdapter.selectedItems.isEmpty()) {
|
||||||
if (!wasSelecting) {
|
if (!wasSelecting) {
|
||||||
val fullPath = PathUtils.path_join(currentDirectoryPath, explorerElements[position].name)
|
val fullPath = PathUtils.pathJoin(currentDirectoryPath, explorerElements[position].name)
|
||||||
when {
|
when {
|
||||||
explorerElements[position].isDirectory -> {
|
explorerElements[position].isDirectory -> {
|
||||||
setCurrentPath(fullPath)
|
setCurrentPath(fullPath)
|
||||||
@ -61,7 +61,7 @@ class ExplorerActivityPick : BaseExplorerActivity() {
|
|||||||
val types = ArrayList<Int>()
|
val types = ArrayList<Int>()
|
||||||
for (i in explorerAdapter.selectedItems) {
|
for (i in explorerAdapter.selectedItems) {
|
||||||
val e = explorerElements[i]
|
val e = explorerElements[i]
|
||||||
paths.add(PathUtils.path_join(currentDirectoryPath, e.name))
|
paths.add(PathUtils.pathJoin(currentDirectoryPath, e.name))
|
||||||
types.add(e.elementType.toInt())
|
types.add(e.elementType.toInt())
|
||||||
}
|
}
|
||||||
resultIntent.putStringArrayListExtra("paths", paths)
|
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) {
|
class ExplorerElement(val name: String, val elementType: Short, var size: Long, mtime: Long, parentPath: String) {
|
||||||
val mTime = Date((mtime * 1000).toString().toLong())
|
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
|
val isDirectory: Boolean
|
||||||
get() = elementType.toInt() == 0
|
get() = elementType.toInt() == 0
|
||||||
|
@ -7,7 +7,7 @@ import androidx.appcompat.app.AppCompatActivity
|
|||||||
import sushi.hardcore.droidfs.R
|
import sushi.hardcore.droidfs.R
|
||||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
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 dialogLoadingView = activity.layoutInflater.inflate(R.layout.dialog_loading, null)
|
||||||
private val dialogLoading: AlertDialog = ColoredAlertDialogBuilder(activity)
|
private val dialogLoading: AlertDialog = ColoredAlertDialogBuilder(activity)
|
||||||
.setView(dialogLoadingView)
|
.setView(dialogLoadingView)
|
||||||
@ -31,7 +31,7 @@ abstract class LoadingTask(private val activity: AppCompatActivity, private val
|
|||||||
activity.runOnUiThread { doFinally(activity) }
|
activity.runOnUiThread { doFinally(activity) }
|
||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
protected fun stopTask(onUiThread: (() -> Unit)?){
|
fun stopTask(onUiThread: (() -> Unit)?){
|
||||||
isStopped = true
|
isStopped = true
|
||||||
dialogLoading.dismiss()
|
dialogLoading.dismiss()
|
||||||
onUiThread?.let {
|
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="export_failed">Export of %s failed.</string>
|
||||||
<string name="success_export">Export successful !</string>
|
<string name="success_export">Export successful !</string>
|
||||||
<string name="success_export_msg">The selected files have been successfully exported.</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="passwords_mismatch">Passwords don\'t match</string>
|
||||||
<string name="dir_not_empty">The selected directory isn\'t empty</string>
|
<string name="dir_not_empty">The selected directory isn\'t empty</string>
|
||||||
<string name="success_volume_create">Volume successfully created !</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="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_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="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_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. You will only have read-only access to this volume.</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_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="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>
|
<string name="slideshow_stopped">Slideshow stopped</string>
|
||||||
@ -182,4 +184,5 @@
|
|||||||
<string name="no_more_images">No more images found.</string>
|
<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_read_doc">You should read it carefully before enabling any of these options.</string>
|
||||||
<string name="usf_doc">Unsafe features documentation</string>
|
<string name="usf_doc">Unsafe features documentation</string>
|
||||||
|
<string name="error_retrieving_filename">Unable to retrieve file name for URI: %s</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user