Safe volume directory picking
This commit is contained in:
parent
fcd382ca8b
commit
9f8b653cc7
@ -1,7 +1,6 @@
|
|||||||
package sushi.hardcore.droidfs
|
package sushi.hardcore.droidfs
|
||||||
|
|
||||||
import android.app.Activity
|
import android.net.Uri
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
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.checkboxes_section.*
|
||||||
import kotlinx.android.synthetic.main.volume_path_section.*
|
import kotlinx.android.synthetic.main.volume_path_section.*
|
||||||
import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter
|
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 sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class ChangePasswordActivity : VolumeActionActivity() {
|
class ChangePasswordActivity : VolumeActionActivity() {
|
||||||
companion object {
|
|
||||||
private const val PICK_DIRECTORY_REQUEST_CODE = 1
|
|
||||||
}
|
|
||||||
private lateinit var savedVolumesAdapter: SavedVolumesAdapter
|
private lateinit var savedVolumesAdapter: SavedVolumesAdapter
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -80,17 +78,12 @@ class ChangePasswordActivity : VolumeActionActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun pickDirectory(view: View?) {
|
fun pickDirectory(view: View?) {
|
||||||
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
safePickDirectory()
|
||||||
startActivityForResult(i, PICK_DIRECTORY_REQUEST_CODE)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onDirectoryPicked(uri: Uri) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
if (PathUtils.isTreeUriOnPrimaryStorage(uri)){
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
val path = PathUtils.getFullPathFromTreeUri(uri, this)
|
||||||
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){
|
if (path != null){
|
||||||
edit_volume_path.setText(path)
|
edit_volume_path.setText(path)
|
||||||
} else {
|
} else {
|
||||||
@ -108,9 +101,6 @@ class ChangePasswordActivity : VolumeActionActivity() {
|
|||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onClickChangePassword(view: View?) {
|
fun onClickChangePassword(view: View?) {
|
||||||
loadVolumePath {
|
loadVolumePath {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package sushi.hardcore.droidfs
|
package sushi.hardcore.droidfs
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
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.checkboxes_section.*
|
||||||
import kotlinx.android.synthetic.main.volume_path_section.*
|
import kotlinx.android.synthetic.main.volume_path_section.*
|
||||||
import sushi.hardcore.droidfs.explorers.ExplorerActivity
|
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 sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class CreateActivity : VolumeActionActivity() {
|
class CreateActivity : VolumeActionActivity() {
|
||||||
companion object {
|
|
||||||
private const val PICK_DIRECTORY_REQUEST_CODE = 1
|
|
||||||
}
|
|
||||||
private var sessionID = -1
|
private var sessionID = -1
|
||||||
private var isStartingExplorer = false
|
private var isStartingExplorer = false
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -44,17 +42,12 @@ class CreateActivity : VolumeActionActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun pickDirectory(view: View?) {
|
fun pickDirectory(view: View?) {
|
||||||
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
safePickDirectory()
|
||||||
startActivityForResult(i, PICK_DIRECTORY_REQUEST_CODE)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onDirectoryPicked(uri: Uri) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
if (PathUtils.isTreeUriOnPrimaryStorage(uri)){
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
val path = PathUtils.getFullPathFromTreeUri(uri, this)
|
||||||
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){
|
if (path != null){
|
||||||
edit_volume_path.setText(path)
|
edit_volume_path.setText(path)
|
||||||
} else {
|
} else {
|
||||||
@ -72,9 +65,6 @@ class CreateActivity : VolumeActionActivity() {
|
|||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onClickCreate(view: View?) {
|
fun onClickCreate(view: View?) {
|
||||||
loadVolumePath {
|
loadVolumePath {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package sushi.hardcore.droidfs
|
package sushi.hardcore.droidfs
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
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.checkboxes_section.*
|
||||||
import kotlinx.android.synthetic.main.volume_path_section.*
|
import kotlinx.android.synthetic.main.volume_path_section.*
|
||||||
import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter
|
import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter
|
||||||
|
import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider
|
||||||
import sushi.hardcore.droidfs.explorers.ExplorerActivity
|
import sushi.hardcore.droidfs.explorers.ExplorerActivity
|
||||||
import sushi.hardcore.droidfs.explorers.ExplorerActivityDrop
|
import sushi.hardcore.droidfs.explorers.ExplorerActivityDrop
|
||||||
import sushi.hardcore.droidfs.explorers.ExplorerActivityPick
|
import sushi.hardcore.droidfs.explorers.ExplorerActivityPick
|
||||||
import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider
|
import sushi.hardcore.droidfs.util.PathUtils
|
||||||
import sushi.hardcore.droidfs.util.*
|
import sushi.hardcore.droidfs.util.WidgetUtil
|
||||||
|
import sushi.hardcore.droidfs.util.Wiper
|
||||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class OpenActivity : VolumeActionActivity() {
|
class OpenActivity : VolumeActionActivity() {
|
||||||
companion object {
|
|
||||||
private const val PICK_DIRECTORY_REQUEST_CODE = 1
|
|
||||||
}
|
|
||||||
private lateinit var savedVolumesAdapter: SavedVolumesAdapter
|
private lateinit var savedVolumesAdapter: SavedVolumesAdapter
|
||||||
private var sessionID = -1
|
private var sessionID = -1
|
||||||
private var isStartingActivity = false
|
private var isStartingActivity = false
|
||||||
private var isFinishingIntentionally = false
|
private var isFinishingIntentionally = false
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_open)
|
setContentView(R.layout.activity_open)
|
||||||
@ -107,17 +107,12 @@ class OpenActivity : VolumeActionActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun pickDirectory(view: View?) {
|
fun pickDirectory(view: View?) {
|
||||||
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
|
||||||
isStartingActivity = true
|
isStartingActivity = true
|
||||||
startActivityForResult(i, PICK_DIRECTORY_REQUEST_CODE)
|
safePickDirectory()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onDirectoryPicked(uri: Uri) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
val path = PathUtils.getFullPathFromTreeUri(uri, this)
|
||||||
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){
|
if (path != null){
|
||||||
edit_volume_path.setText(path)
|
edit_volume_path.setText(path)
|
||||||
} else {
|
} else {
|
||||||
@ -128,9 +123,6 @@ class OpenActivity : VolumeActionActivity() {
|
|||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onClickOpen(view: View?) {
|
fun onClickOpen(view: View?) {
|
||||||
loadVolumePath {
|
loadVolumePath {
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package sushi.hardcore.droidfs
|
package sushi.hardcore.droidfs
|
||||||
|
|
||||||
import android.app.KeyguardManager
|
import android.app.KeyguardManager
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.security.keystore.KeyGenParameterSpec
|
import android.security.keystore.KeyGenParameterSpec
|
||||||
import android.security.keystore.KeyPermanentlyInvalidatedException
|
import android.security.keystore.KeyPermanentlyInvalidatedException
|
||||||
@ -9,6 +11,7 @@ import android.security.keystore.KeyProperties
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.biometric.BiometricManager
|
import androidx.biometric.BiometricManager
|
||||||
import androidx.biometric.BiometricPrompt
|
import androidx.biometric.BiometricPrompt
|
||||||
@ -23,10 +26,15 @@ import java.security.KeyStore
|
|||||||
import javax.crypto.*
|
import javax.crypto.*
|
||||||
import javax.crypto.spec.GCMParameterSpec
|
import javax.crypto.spec.GCMParameterSpec
|
||||||
|
|
||||||
open class VolumeActionActivity : BaseActivity() {
|
abstract class VolumeActionActivity : BaseActivity() {
|
||||||
protected lateinit var currentVolumeName: String
|
protected lateinit var currentVolumeName: String
|
||||||
protected lateinit var currentVolumePath: String
|
protected lateinit var currentVolumePath: String
|
||||||
protected lateinit var volumeDatabase: VolumeDatabase
|
protected lateinit var volumeDatabase: VolumeDatabase
|
||||||
|
protected val pickDirectory = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
|
||||||
|
if (uri != null) {
|
||||||
|
onDirectoryPicked(uri)
|
||||||
|
}
|
||||||
|
}
|
||||||
private var usf_fingerprint = false
|
private var usf_fingerprint = false
|
||||||
private var biometricCanAuthenticateCode: Int = -1
|
private var biometricCanAuthenticateCode: Int = -1
|
||||||
private lateinit var biometricManager: BiometricManager
|
private lateinit var biometricManager: BiometricManager
|
||||||
@ -48,6 +56,20 @@ open class VolumeActionActivity : BaseActivity() {
|
|||||||
private const val GCM_TAG_LEN = 128
|
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(){
|
protected fun setupFingerprintStuff(){
|
||||||
originalHiddenVolumeSectionLayoutParams = hidden_volume_section.layoutParams as LinearLayout.LayoutParams
|
originalHiddenVolumeSectionLayoutParams = hidden_volume_section.layoutParams as LinearLayout.LayoutParams
|
||||||
originalNormalVolumeSectionLayoutParams = normal_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) {
|
return if (!keyguardManager.isKeyguardSecure) {
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
when (biometricManager.canAuthenticate()){
|
when (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG)){
|
||||||
BiometricManager.BIOMETRIC_SUCCESS -> 0
|
BiometricManager.BIOMETRIC_SUCCESS -> 0
|
||||||
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> 2
|
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> 2
|
||||||
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> 3
|
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> 3
|
||||||
@ -209,7 +231,7 @@ open class VolumeActionActivity : BaseActivity() {
|
|||||||
.setSubtitle(getString(R.string.encrypt_action_description))
|
.setSubtitle(getString(R.string.encrypt_action_description))
|
||||||
.setDescription(getString(R.string.fingerprint_instruction))
|
.setDescription(getString(R.string.fingerprint_instruction))
|
||||||
.setNegativeButtonText(getString(R.string.cancel))
|
.setNegativeButtonText(getString(R.string.cancel))
|
||||||
.setDeviceCredentialAllowed(false)
|
.setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG)
|
||||||
.setConfirmationRequired(false)
|
.setConfirmationRequired(false)
|
||||||
.build()
|
.build()
|
||||||
if (!isCipherReady){
|
if (!isCipherReady){
|
||||||
@ -233,7 +255,7 @@ open class VolumeActionActivity : BaseActivity() {
|
|||||||
.setSubtitle(getString(R.string.decrypt_action_description))
|
.setSubtitle(getString(R.string.decrypt_action_description))
|
||||||
.setDescription(getString(R.string.fingerprint_instruction))
|
.setDescription(getString(R.string.fingerprint_instruction))
|
||||||
.setNegativeButtonText(getString(R.string.cancel))
|
.setNegativeButtonText(getString(R.string.cancel))
|
||||||
.setDeviceCredentialAllowed(false)
|
.setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG)
|
||||||
.setConfirmationRequired(false)
|
.setConfirmationRequired(false)
|
||||||
.build()
|
.build()
|
||||||
this.onPasswordDecrypted = onPasswordDecrypted
|
this.onPasswordDecrypted = onPasswordDecrypted
|
||||||
|
@ -2,35 +2,148 @@ package sushi.hardcore.droidfs.explorers
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import sushi.hardcore.droidfs.CameraActivity
|
import sushi.hardcore.droidfs.CameraActivity
|
||||||
|
import sushi.hardcore.droidfs.GocryptfsVolume
|
||||||
import sushi.hardcore.droidfs.OpenActivity
|
import sushi.hardcore.droidfs.OpenActivity
|
||||||
import sushi.hardcore.droidfs.R
|
import sushi.hardcore.droidfs.R
|
||||||
import sushi.hardcore.droidfs.adapters.IconTextDialogAdapter
|
import sushi.hardcore.droidfs.adapters.IconTextDialogAdapter
|
||||||
import sushi.hardcore.droidfs.file_operations.OperationFile
|
|
||||||
import sushi.hardcore.droidfs.content_providers.ExternalProvider
|
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.util.PathUtils
|
||||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class ExplorerActivity : BaseExplorerActivity() {
|
class ExplorerActivity : BaseExplorerActivity() {
|
||||||
companion object {
|
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 enum class ItemsActions {NONE, COPY, MOVE}
|
||||||
}
|
}
|
||||||
private var usf_decrypt = false
|
private var usf_decrypt = false
|
||||||
private var usf_share = false
|
private var usf_share = false
|
||||||
private var currentItemAction = ItemsActions.NONE
|
private var currentItemAction = ItemsActions.NONE
|
||||||
private val itemsToProcess = ArrayList<OperationFile>()
|
private val itemsToProcess = ArrayList<OperationFile>()
|
||||||
|
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<OperationFile>()
|
||||||
|
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() {
|
override fun init() {
|
||||||
setContentView(R.layout.activity_explorer)
|
setContentView(R.layout.activity_explorer)
|
||||||
usf_decrypt = sharedPrefs.getBoolean("usf_decrypt", false)
|
usf_decrypt = sharedPrefs.getBoolean("usf_decrypt", false)
|
||||||
@ -82,15 +195,11 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
intent.action = "pick"
|
intent.action = "pick"
|
||||||
intent.putExtra("sessionID", gocryptfsVolume.sessionID)
|
intent.putExtra("sessionID", gocryptfsVolume.sessionID)
|
||||||
isStartingActivity = true
|
isStartingActivity = true
|
||||||
startActivityForResult(intent, PICK_OTHER_VOLUME_ITEMS_REQUEST_CODE)
|
pickFromOtherVolumes.launch(intent)
|
||||||
}
|
}
|
||||||
"importFiles" -> {
|
"importFiles" -> {
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
|
||||||
intent.type = "*/*"
|
|
||||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
|
||||||
isStartingActivity = true
|
isStartingActivity = true
|
||||||
startActivityForResult(intent, PICK_FILES_REQUEST_CODE)
|
pickFiles.launch(arrayOf("*/*"))
|
||||||
}
|
}
|
||||||
"createFile" -> {
|
"createFile" -> {
|
||||||
val dialogEditTextView = layoutInflater.inflate(R.layout.dialog_edit_text, null)
|
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<Uri> = 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<OperationFile>()
|
|
||||||
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 {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
menuInflater.inflate(R.menu.explorer, menu)
|
menuInflater.inflate(R.menu.explorer, menu)
|
||||||
if (currentItemAction != ItemsActions.NONE) {
|
if (currentItemAction != ItemsActions.NONE) {
|
||||||
@ -398,9 +377,8 @@ class ExplorerActivity : BaseExplorerActivity() {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.decrypt -> {
|
R.id.decrypt -> {
|
||||||
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
|
||||||
isStartingActivity = true
|
isStartingActivity = true
|
||||||
startActivityForResult(i, PICK_DIRECTORY_REQUEST_CODE)
|
pickDirectory.launch(null)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
else -> super.onOptionsItemSelected(item)
|
else -> super.onOptionsItemSelected(item)
|
||||||
|
@ -194,4 +194,5 @@
|
|||||||
<string name="folders_first_summary">Show folders at the beginning of the list</string>
|
<string name="folders_first_summary">Show folders at the beginning of the list</string>
|
||||||
<string name="auto_fit_title">Video player screen auto-rotation</string>
|
<string name="auto_fit_title">Video player screen auto-rotation</string>
|
||||||
<string name="auto_fit_summary">Auto-rotate the screen to fit video dimensions</string>
|
<string name="auto_fit_summary">Auto-rotate the screen to fit video dimensions</string>
|
||||||
|
<string name="open_tree_failed">No file explorer found. Please install one and retry.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user