From 9f8b653cc71eaa6745033393f808bdc5d281de6c Mon Sep 17 00:00:00 2001 From: Hardcore Sushi Date: Mon, 7 Jun 2021 14:12:40 +0200 Subject: [PATCH] Safe volume directory picking --- .../droidfs/ChangePasswordActivity.kt | 54 ++-- .../sushi/hardcore/droidfs/CreateActivity.kt | 52 ++-- .../sushi/hardcore/droidfs/OpenActivity.kt | 42 ++- .../hardcore/droidfs/VolumeActionActivity.kt | 30 +- .../droidfs/explorers/ExplorerActivity.kt | 266 ++++++++---------- app/src/main/res/values/strings.xml | 1 + 6 files changed, 209 insertions(+), 236 deletions(-) diff --git a/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt index 6711ec6..5ae55cf 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt @@ -1,7 +1,6 @@ package sushi.hardcore.droidfs -import android.app.Activity -import android.content.Intent +import android.net.Uri import android.os.Build import android.os.Bundle import android.text.Editable @@ -14,15 +13,14 @@ import kotlinx.android.synthetic.main.activity_change_password.* import kotlinx.android.synthetic.main.checkboxes_section.* import kotlinx.android.synthetic.main.volume_path_section.* import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter -import sushi.hardcore.droidfs.util.* +import sushi.hardcore.droidfs.util.PathUtils +import sushi.hardcore.droidfs.util.WidgetUtil +import sushi.hardcore.droidfs.util.Wiper import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import java.io.File import java.util.* class ChangePasswordActivity : VolumeActionActivity() { - companion object { - private const val PICK_DIRECTORY_REQUEST_CODE = 1 - } private lateinit var savedVolumesAdapter: SavedVolumesAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -80,35 +78,27 @@ class ChangePasswordActivity : VolumeActionActivity() { } fun pickDirectory(view: View?) { - val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) - startActivityForResult(i, PICK_DIRECTORY_REQUEST_CODE) + safePickDirectory() } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - 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) - } else { - ColoredAlertDialogBuilder(this) - .setTitle(R.string.error) - .setMessage(R.string.path_from_uri_null_error_msg) - .setPositiveButton(R.string.ok, null) - .show() - } - } else { - ColoredAlertDialogBuilder(this) - .setTitle(R.string.warning) - .setMessage(R.string.change_pwd_on_sdcard_error_msg) - .setPositiveButton(R.string.ok, null) - .show() - } - } + override fun onDirectoryPicked(uri: Uri) { + if (PathUtils.isTreeUriOnPrimaryStorage(uri)){ + val path = PathUtils.getFullPathFromTreeUri(uri, this) + if (path != null){ + 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 { + ColoredAlertDialogBuilder(this) + .setTitle(R.string.warning) + .setMessage(R.string.change_pwd_on_sdcard_error_msg) + .setPositiveButton(R.string.ok, null) + .show() } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/CreateActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/CreateActivity.kt index 50a92f3..bcd8191 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/CreateActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/CreateActivity.kt @@ -1,7 +1,7 @@ package sushi.hardcore.droidfs -import android.app.Activity import android.content.Intent +import android.net.Uri import android.os.Build import android.os.Bundle import android.view.View @@ -11,15 +11,13 @@ import kotlinx.android.synthetic.main.activity_create.* import kotlinx.android.synthetic.main.checkboxes_section.* import kotlinx.android.synthetic.main.volume_path_section.* import sushi.hardcore.droidfs.explorers.ExplorerActivity -import sushi.hardcore.droidfs.util.* +import sushi.hardcore.droidfs.util.PathUtils +import sushi.hardcore.droidfs.util.Wiper import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import java.io.File import java.util.* class CreateActivity : VolumeActionActivity() { - companion object { - private const val PICK_DIRECTORY_REQUEST_CODE = 1 - } private var sessionID = -1 private var isStartingExplorer = false override fun onCreate(savedInstanceState: Bundle?) { @@ -44,35 +42,27 @@ class CreateActivity : VolumeActionActivity() { } fun pickDirectory(view: View?) { - val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) - startActivityForResult(i, PICK_DIRECTORY_REQUEST_CODE) + safePickDirectory() } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - 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) - } else { - ColoredAlertDialogBuilder(this) - .setTitle(R.string.error) - .setMessage(R.string.path_from_uri_null_error_msg) - .setPositiveButton(R.string.ok, null) - .show() - } - } else { - ColoredAlertDialogBuilder(this) - .setTitle(R.string.warning) - .setMessage(R.string.create_on_sdcard_error_msg) - .setPositiveButton(R.string.ok, null) - .show() - } - } + override fun onDirectoryPicked(uri: Uri) { + if (PathUtils.isTreeUriOnPrimaryStorage(uri)){ + val path = PathUtils.getFullPathFromTreeUri(uri, this) + if (path != null){ + 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 { + ColoredAlertDialogBuilder(this) + .setTitle(R.string.warning) + .setMessage(R.string.create_on_sdcard_error_msg) + .setPositiveButton(R.string.ok, null) + .show() } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/OpenActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/OpenActivity.kt index 230453a..11f1cd5 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/OpenActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/OpenActivity.kt @@ -1,7 +1,7 @@ package sushi.hardcore.droidfs -import android.app.Activity import android.content.Intent +import android.net.Uri import android.os.Build import android.os.Bundle import android.text.Editable @@ -14,23 +14,23 @@ import kotlinx.android.synthetic.main.activity_open.* import kotlinx.android.synthetic.main.checkboxes_section.* import kotlinx.android.synthetic.main.volume_path_section.* import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter +import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider import sushi.hardcore.droidfs.explorers.ExplorerActivity import sushi.hardcore.droidfs.explorers.ExplorerActivityDrop import sushi.hardcore.droidfs.explorers.ExplorerActivityPick -import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider -import sushi.hardcore.droidfs.util.* +import sushi.hardcore.droidfs.util.PathUtils +import sushi.hardcore.droidfs.util.WidgetUtil +import sushi.hardcore.droidfs.util.Wiper import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import java.io.File import java.util.* class OpenActivity : VolumeActionActivity() { - companion object { - private const val PICK_DIRECTORY_REQUEST_CODE = 1 - } private lateinit var savedVolumesAdapter: SavedVolumesAdapter private var sessionID = -1 private var isStartingActivity = false private var isFinishingIntentionally = false + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_open) @@ -107,28 +107,20 @@ class OpenActivity : VolumeActionActivity() { } fun pickDirectory(view: View?) { - val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) isStartingActivity = true - startActivityForResult(i, PICK_DIRECTORY_REQUEST_CODE) + safePickDirectory() } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - if (resultCode == Activity.RESULT_OK) { - if (requestCode == PICK_DIRECTORY_REQUEST_CODE) { - if (data?.data != null) { - val path = PathUtils.getFullPathFromTreeUri(data.data, this) - if (path != null){ - 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() - } - } - } + override fun onDirectoryPicked(uri: Uri) { + val path = PathUtils.getFullPathFromTreeUri(uri, this) + if (path != null){ + 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() } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/VolumeActionActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/VolumeActionActivity.kt index 1eaf85b..cca7655 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/VolumeActionActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/VolumeActionActivity.kt @@ -1,7 +1,9 @@ package sushi.hardcore.droidfs import android.app.KeyguardManager +import android.content.ActivityNotFoundException import android.content.Context +import android.net.Uri import android.os.Build import android.security.keystore.KeyGenParameterSpec import android.security.keystore.KeyPermanentlyInvalidatedException @@ -9,6 +11,7 @@ import android.security.keystore.KeyProperties import android.view.View import android.widget.LinearLayout import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi import androidx.biometric.BiometricManager import androidx.biometric.BiometricPrompt @@ -23,10 +26,15 @@ import java.security.KeyStore import javax.crypto.* import javax.crypto.spec.GCMParameterSpec -open class VolumeActionActivity : BaseActivity() { +abstract class VolumeActionActivity : BaseActivity() { protected lateinit var currentVolumeName: String protected lateinit var currentVolumePath: String protected lateinit var volumeDatabase: VolumeDatabase + protected val pickDirectory = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri -> + if (uri != null) { + onDirectoryPicked(uri) + } + } private var usf_fingerprint = false private var biometricCanAuthenticateCode: Int = -1 private lateinit var biometricManager: BiometricManager @@ -48,6 +56,20 @@ open class VolumeActionActivity : BaseActivity() { private const val GCM_TAG_LEN = 128 } + protected abstract fun onDirectoryPicked(uri: Uri) + + protected fun safePickDirectory() { + try { + pickDirectory.launch(null) + } catch (e: ActivityNotFoundException) { + ColoredAlertDialogBuilder(this) + .setTitle(R.string.error) + .setMessage(R.string.open_tree_failed) + .setPositiveButton(R.string.ok, null) + .show() + } + } + protected fun setupFingerprintStuff(){ originalHiddenVolumeSectionLayoutParams = hidden_volume_section.layoutParams as LinearLayout.LayoutParams originalNormalVolumeSectionLayoutParams = normal_volume_section.layoutParams as LinearLayout.LayoutParams @@ -137,7 +159,7 @@ open class VolumeActionActivity : BaseActivity() { return if (!keyguardManager.isKeyguardSecure) { 1 } else { - when (biometricManager.canAuthenticate()){ + when (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG)){ BiometricManager.BIOMETRIC_SUCCESS -> 0 BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> 2 BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> 3 @@ -209,7 +231,7 @@ open class VolumeActionActivity : BaseActivity() { .setSubtitle(getString(R.string.encrypt_action_description)) .setDescription(getString(R.string.fingerprint_instruction)) .setNegativeButtonText(getString(R.string.cancel)) - .setDeviceCredentialAllowed(false) + .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG) .setConfirmationRequired(false) .build() if (!isCipherReady){ @@ -233,7 +255,7 @@ open class VolumeActionActivity : BaseActivity() { .setSubtitle(getString(R.string.decrypt_action_description)) .setDescription(getString(R.string.fingerprint_instruction)) .setNegativeButtonText(getString(R.string.cancel)) - .setDeviceCredentialAllowed(false) + .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG) .setConfirmationRequired(false) .build() this.onPasswordDecrypted = onPasswordDecrypted diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt index 306d60d..38e4cd8 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt @@ -2,35 +2,148 @@ package sushi.hardcore.droidfs.explorers import android.app.Activity import android.content.Intent -import android.net.Uri import android.view.Menu import android.view.MenuItem import android.view.View import android.view.WindowManager import android.widget.EditText import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts import sushi.hardcore.droidfs.CameraActivity +import sushi.hardcore.droidfs.GocryptfsVolume import sushi.hardcore.droidfs.OpenActivity import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.adapters.IconTextDialogAdapter -import sushi.hardcore.droidfs.file_operations.OperationFile import sushi.hardcore.droidfs.content_providers.ExternalProvider -import sushi.hardcore.droidfs.GocryptfsVolume +import sushi.hardcore.droidfs.file_operations.OperationFile import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import java.io.File class ExplorerActivity : BaseExplorerActivity() { companion object { - private const val PICK_DIRECTORY_REQUEST_CODE = 1 - private const val PICK_FILES_REQUEST_CODE = 2 - private const val PICK_OTHER_VOLUME_ITEMS_REQUEST_CODE = 3 private enum class ItemsActions {NONE, COPY, MOVE} } private var usf_decrypt = false private var usf_share = false private var currentItemAction = ItemsActions.NONE private val itemsToProcess = ArrayList() + private val pickFromOtherVolumes = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == Activity.RESULT_OK) { + result.data?.let { resultIntent -> + val remoteSessionID = resultIntent.getIntExtra("sessionID", -1) + val remoteGocryptfsVolume = GocryptfsVolume(remoteSessionID) + val path = resultIntent.getStringExtra("path") + val operationFiles = ArrayList() + if (path == null){ //multiples elements + val paths = resultIntent.getStringArrayListExtra("paths") + val types = resultIntent.getIntegerArrayListExtra("types") + if (types != null && paths != null){ + for (i in paths.indices) { + operationFiles.add( + OperationFile.fromExplorerElement( + ExplorerElement(File(paths[i]).name, types[i].toShort(), -1, -1, PathUtils.getParentPath(paths[i])) + ) + ) + if (types[i] == 0){ //directory + remoteGocryptfsVolume.recursiveMapFiles(paths[i]).forEach { + operationFiles.add(OperationFile.fromExplorerElement(it)) + } + } + } + } + } else { + operationFiles.add( + OperationFile.fromExplorerElement( + ExplorerElement(File(path).name, 1, -1, -1, PathUtils.getParentPath(path)) + ) + ) + } + if (operationFiles.size > 0){ + checkPathOverwrite(operationFiles, currentDirectoryPath) { items -> + if (items == null) { + remoteGocryptfsVolume.close() + } else { + fileOperationService.copyElements(items, remoteGocryptfsVolume){ failedItem -> + runOnUiThread { + if (failedItem == null){ + Toast.makeText(this, R.string.success_import, Toast.LENGTH_SHORT).show() + } else { + ColoredAlertDialogBuilder(this) + .setTitle(R.string.error) + .setMessage(getString(R.string.import_failed, failedItem)) + .setPositiveButton(R.string.ok, null) + .show() + } + setCurrentPath(currentDirectoryPath) + } + remoteGocryptfsVolume.close() + } + } + } + } else { + remoteGocryptfsVolume.close() + } + } + } + } + private val pickFiles = registerForActivityResult(ActivityResultContracts.OpenMultipleDocuments()) { uris -> + if (uris != null) { + importFilesFromUris(uris){ failedItem -> + if (failedItem == null){ + ColoredAlertDialogBuilder(this) + .setTitle(R.string.success_import) + .setMessage(""" + ${getString(R.string.success_import_msg)} + ${getString(R.string.ask_for_wipe)} + """.trimIndent()) + .setPositiveButton(R.string.yes) { _, _ -> + fileOperationService.wipeUris(uris) { errorMsg -> + runOnUiThread { + if (errorMsg == null){ + Toast.makeText(this, R.string.wipe_successful, Toast.LENGTH_SHORT).show() + } else { + ColoredAlertDialogBuilder(this) + .setTitle(R.string.error) + .setMessage(getString(R.string.wipe_failed, errorMsg)) + .setPositiveButton(R.string.ok, null) + .show() + } + } + } + } + .setNegativeButton(R.string.no, null) + .show() + } else { + ColoredAlertDialogBuilder(this) + .setTitle(R.string.error) + .setMessage(getString(R.string.import_failed, failedItem)) + .setPositiveButton(R.string.ok, null) + .show() + } + setCurrentPath(currentDirectoryPath) + } + } + } + private val pickDirectory = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri -> + if (uri != null) { + fileOperationService.exportFiles(uri, explorerAdapter.selectedItems.map { i -> explorerElements[i] }){ failedItem -> + runOnUiThread { + if (failedItem == null){ + Toast.makeText(this, R.string.success_export, Toast.LENGTH_SHORT).show() + } else { + ColoredAlertDialogBuilder(this) + .setTitle(R.string.error) + .setMessage(getString(R.string.export_failed, failedItem)) + .setPositiveButton(R.string.ok, null) + .show() + } + } + } + } + unselectAll() + } + override fun init() { setContentView(R.layout.activity_explorer) usf_decrypt = sharedPrefs.getBoolean("usf_decrypt", false) @@ -82,15 +195,11 @@ class ExplorerActivity : BaseExplorerActivity() { intent.action = "pick" intent.putExtra("sessionID", gocryptfsVolume.sessionID) isStartingActivity = true - startActivityForResult(intent, PICK_OTHER_VOLUME_ITEMS_REQUEST_CODE) + pickFromOtherVolumes.launch(intent) } "importFiles" -> { - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) - intent.type = "*/*" - intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true) - intent.addCategory(Intent.CATEGORY_OPENABLE) isStartingActivity = true - startActivityForResult(intent, PICK_FILES_REQUEST_CODE) + pickFiles.launch(arrayOf("*/*")) } "createFile" -> { val dialogEditTextView = layoutInflater.inflate(R.layout.dialog_edit_text, null) @@ -132,136 +241,6 @@ class ExplorerActivity : BaseExplorerActivity() { } } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - if (requestCode == PICK_FILES_REQUEST_CODE) { - if (resultCode == Activity.RESULT_OK && data != null) { - val uris: MutableList = ArrayList() - val singleUri = data.data - if (singleUri == null) { //multiples choices - val clipData = data.clipData - if (clipData != null){ - for (i in 0 until clipData.itemCount) { - uris.add(clipData.getItemAt(i).uri) - } - } - } else { - uris.add(singleUri) - } - importFilesFromUris(uris){ failedItem -> - if (failedItem == null){ - ColoredAlertDialogBuilder(this) - .setTitle(R.string.success_import) - .setMessage(""" - ${getString(R.string.success_import_msg)} - ${getString(R.string.ask_for_wipe)} - """.trimIndent()) - .setPositiveButton(R.string.yes) { _, _ -> - fileOperationService.wipeUris(uris) { errorMsg -> - runOnUiThread { - if (errorMsg == null){ - Toast.makeText(this, R.string.wipe_successful, Toast.LENGTH_SHORT).show() - } else { - ColoredAlertDialogBuilder(this) - .setTitle(R.string.error) - .setMessage(getString(R.string.wipe_failed, errorMsg)) - .setPositiveButton(R.string.ok, null) - .show() - } - } - - } - } - .setNegativeButton(R.string.no, null) - .show() - } else { - ColoredAlertDialogBuilder(this) - .setTitle(R.string.error) - .setMessage(getString(R.string.import_failed, failedItem)) - .setPositiveButton(R.string.ok, null) - .show() - } - setCurrentPath(currentDirectoryPath) - } - } - } else if (requestCode == PICK_DIRECTORY_REQUEST_CODE) { - if (resultCode == Activity.RESULT_OK && data != null) { - data.data?.let { uri -> - fileOperationService.exportFiles(uri, explorerAdapter.selectedItems.map { i -> explorerElements[i] }){ failedItem -> - runOnUiThread { - if (failedItem == null){ - Toast.makeText(this, R.string.success_export, Toast.LENGTH_SHORT).show() - } else { - ColoredAlertDialogBuilder(this) - .setTitle(R.string.error) - .setMessage(getString(R.string.export_failed, failedItem)) - .setPositiveButton(R.string.ok, null) - .show() - } - } - } - unselectAll() - } - } - } else if (requestCode == PICK_OTHER_VOLUME_ITEMS_REQUEST_CODE) { - if (resultCode == Activity.RESULT_OK && data != null) { - val remoteSessionID = data.getIntExtra("sessionID", -1) - val remoteGocryptfsVolume = GocryptfsVolume(remoteSessionID) - val path = data.getStringExtra("path") - val operationFiles = ArrayList() - if (path == null){ //multiples elements - val paths = data.getStringArrayListExtra("paths") - val types = data.getIntegerArrayListExtra("types") - if (types != null && paths != null){ - for (i in paths.indices) { - operationFiles.add( - OperationFile.fromExplorerElement( - ExplorerElement(File(paths[i]).name, types[i].toShort(), -1, -1, PathUtils.getParentPath(paths[i])) - ) - ) - if (types[i] == 0){ //directory - remoteGocryptfsVolume.recursiveMapFiles(paths[i]).forEach { - operationFiles.add(OperationFile.fromExplorerElement(it)) - } - } - } - } - } else { - operationFiles.add( - OperationFile.fromExplorerElement( - ExplorerElement(File(path).name, 1, -1, -1, PathUtils.getParentPath(path)) - ) - ) - } - if (operationFiles.size > 0){ - checkPathOverwrite(operationFiles, currentDirectoryPath) { items -> - if (items == null) { - remoteGocryptfsVolume.close() - } else { - fileOperationService.copyElements(items, remoteGocryptfsVolume){ failedItem -> - runOnUiThread { - if (failedItem == null){ - Toast.makeText(this, R.string.success_import, Toast.LENGTH_SHORT).show() - } else { - ColoredAlertDialogBuilder(this) - .setTitle(R.string.error) - .setMessage(getString(R.string.import_failed, failedItem)) - .setPositiveButton(R.string.ok, null) - .show() - } - setCurrentPath(currentDirectoryPath) - } - remoteGocryptfsVolume.close() - } - } - } - } else { - remoteGocryptfsVolume.close() - } - } - } - } - override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.explorer, menu) if (currentItemAction != ItemsActions.NONE) { @@ -398,9 +377,8 @@ class ExplorerActivity : BaseExplorerActivity() { true } R.id.decrypt -> { - val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) isStartingActivity = true - startActivityForResult(i, PICK_DIRECTORY_REQUEST_CODE) + pickDirectory.launch(null) true } else -> super.onOptionsItemSelected(item) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f85754a..df5fc75 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -194,4 +194,5 @@ Show folders at the beginning of the list Video player screen auto-rotation Auto-rotate the screen to fit video dimensions + No file explorer found. Please install one and retry.