Explorer loading dialogs & Logo fix

This commit is contained in:
Hardcore Sushi 2020-07-28 22:25:10 +02:00
parent 2571849bc3
commit 34d7f19927
19 changed files with 482 additions and 455 deletions

View File

@ -15,7 +15,7 @@ android {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 29
versionCode 1 versionCode 1
versionName "1.1.0" versionName "1.1.1"
ndk { ndk {
abiFilters 'x86_64', 'armeabi-v7a', 'arm64-v8a' abiFilters 'x86_64', 'armeabi-v7a', 'arm64-v8a'

View File

@ -3,7 +3,6 @@ package sushi.hardcore.droidfs
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.view.WindowManager import android.view.WindowManager
import android.widget.Toast
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.jaredrummler.cyanea.app.CyaneaAppCompatActivity import com.jaredrummler.cyanea.app.CyaneaAppCompatActivity
@ -30,8 +29,4 @@ open class BaseActivity: CyaneaAppCompatActivity() {
} }
} }
} }
protected fun toastFromThread(stringId: Int){
runOnUiThread { Toast.makeText(this, stringId, Toast.LENGTH_SHORT).show() }
}
} }

View File

@ -8,8 +8,8 @@ import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.view.View import android.view.View
import android.widget.AdapterView.OnItemClickListener import android.widget.AdapterView.OnItemClickListener
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_change_password.* import kotlinx.android.synthetic.main.activity_change_password.*
import kotlinx.android.synthetic.main.activity_change_password.checkbox_remember_path import kotlinx.android.synthetic.main.activity_change_password.checkbox_remember_path
import kotlinx.android.synthetic.main.activity_change_password.checkbox_save_password import kotlinx.android.synthetic.main.activity_change_password.checkbox_save_password
@ -18,10 +18,7 @@ import kotlinx.android.synthetic.main.activity_change_password.saved_path_listvi
import kotlinx.android.synthetic.main.toolbar.* import kotlinx.android.synthetic.main.toolbar.*
import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter
import sushi.hardcore.droidfs.fingerprint_stuff.FingerprintPasswordHashSaver import sushi.hardcore.droidfs.fingerprint_stuff.FingerprintPasswordHashSaver
import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.util.*
import sushi.hardcore.droidfs.util.GocryptfsVolume
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.util.* import java.util.*
@ -59,8 +56,11 @@ class ChangePasswordActivity : BaseActivity() {
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
if (sharedPrefs.getString(s.toString(), null) == null) { if (sharedPrefs.getString(s.toString(), null) == null) {
edit_old_password.hint = null edit_old_password.hint = null
edit_old_password.isEnabled = true
} else { } else {
edit_old_password.text = null
edit_old_password.hint = getString(R.string.hash_saved_hint) edit_old_password.hint = getString(R.string.hash_saved_hint)
edit_old_password.isEnabled = false
} }
} }
}) })
@ -97,21 +97,12 @@ class ChangePasswordActivity : BaseActivity() {
} }
private fun changePassword(givenHash: ByteArray?){ private fun changePassword(givenHash: ByteArray?){
val dialogLoadingView = layoutInflater.inflate(R.layout.dialog_loading, null) object : LoadingTask(this, R.string.loading_msg_change_password){
val dialogTextMessage = dialogLoadingView.findViewById<TextView>(R.id.text_message) override fun doTask(activity: AppCompatActivity) {
dialogTextMessage.text = getString(R.string.loading_msg_change_password)
val dialogLoading = ColoredAlertDialogBuilder(this)
.setView(dialogLoadingView)
.setTitle(R.string.loading)
.setCancelable(false)
.create()
dialogLoading.show()
Thread {
val newPassword = edit_new_password.text.toString().toCharArray() val newPassword = edit_new_password.text.toString().toCharArray()
val newPasswordConfirm = edit_new_password_confirm.text.toString().toCharArray() val newPasswordConfirm = edit_new_password_confirm.text.toString().toCharArray()
if (!newPassword.contentEquals(newPasswordConfirm)) { if (!newPassword.contentEquals(newPasswordConfirm)) {
dialogLoading.dismiss() stopTaskWithToast(R.string.passwords_mismatch)
toastFromThread(R.string.passwords_mismatch)
} else { } else {
val oldPassword = edit_old_password.text.toString().toCharArray() val oldPassword = edit_old_password.text.toString().toCharArray()
var returnedHash: ByteArray? = null var returnedHash: ByteArray? = null
@ -122,8 +113,9 @@ class ChangePasswordActivity : BaseActivity() {
if (givenHash == null){ if (givenHash == null){
val cipherText = sharedPrefs.getString(rootCipherDir, null) val cipherText = sharedPrefs.getString(rootCipherDir, null)
if (cipherText != null){ //password hash saved if (cipherText != null){ //password hash saved
dialogLoading.dismiss() stopTask {
fingerprintPasswordHashSaver.decrypt(cipherText, rootCipherDir, ::changePassword) fingerprintPasswordHashSaver.decrypt(cipherText, rootCipherDir, ::changePassword)
}
changePasswordImmediately = false changePasswordImmediately = false
} }
} }
@ -144,21 +136,18 @@ class ChangePasswordActivity : BaseActivity() {
editor.apply() editor.apply()
} }
if (checkbox_save_password.isChecked && returnedHash != null){ if (checkbox_save_password.isChecked && returnedHash != null){
dialogLoading.dismiss()
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir){ _ -> fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir){ _ ->
onPasswordChanged() stopTask { onPasswordChanged() }
} }
continueImmediately = false continueImmediately = false
} }
} }
if (continueImmediately){ if (continueImmediately){
dialogLoading.dismiss() stopTask { onPasswordChanged() }
runOnUiThread { onPasswordChanged() }
} }
} else { } else {
dialogLoading.dismiss() stopTask {
runOnUiThread { ColoredAlertDialogBuilder(activity)
ColoredAlertDialogBuilder(this)
.setTitle(R.string.error) .setTitle(R.string.error)
.setMessage(R.string.change_password_failed) .setMessage(R.string.change_password_failed)
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
@ -170,7 +159,8 @@ class ChangePasswordActivity : BaseActivity() {
} }
Arrays.fill(newPassword, 0.toChar()) Arrays.fill(newPassword, 0.toChar())
Arrays.fill(newPasswordConfirm, 0.toChar()) Arrays.fill(newPasswordConfirm, 0.toChar())
}.start() }
}
} }
private fun onPasswordChanged(){ private fun onPasswordChanged(){

View File

@ -5,7 +5,7 @@ import android.content.Intent
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.widget.TextView import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_create.* import kotlinx.android.synthetic.main.activity_create.*
import kotlinx.android.synthetic.main.activity_create.checkbox_remember_path import kotlinx.android.synthetic.main.activity_create.checkbox_remember_path
import kotlinx.android.synthetic.main.activity_create.checkbox_save_password import kotlinx.android.synthetic.main.activity_create.checkbox_save_password
@ -14,10 +14,7 @@ import kotlinx.android.synthetic.main.activity_create.edit_volume_path
import kotlinx.android.synthetic.main.toolbar.* import kotlinx.android.synthetic.main.toolbar.*
import sushi.hardcore.droidfs.explorers.ExplorerActivity import sushi.hardcore.droidfs.explorers.ExplorerActivity
import sushi.hardcore.droidfs.fingerprint_stuff.FingerprintPasswordHashSaver import sushi.hardcore.droidfs.fingerprint_stuff.FingerprintPasswordHashSaver
import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.util.*
import sushi.hardcore.droidfs.util.GocryptfsVolume
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.*
@ -64,21 +61,12 @@ class CreateActivity : BaseActivity() {
} }
fun onClickCreate(view: View?) { fun onClickCreate(view: View?) {
val dialogLoadingView = layoutInflater.inflate(R.layout.dialog_loading, null) object: LoadingTask(this, R.string.loading_msg_create){
val dialogTextMessage = dialogLoadingView.findViewById<TextView>(R.id.text_message) override fun doTask(activity: AppCompatActivity) {
dialogTextMessage.text = getString(R.string.loading_msg_create)
val dialogLoading = ColoredAlertDialogBuilder(this)
.setView(dialogLoadingView)
.setTitle(R.string.loading)
.setCancelable(false)
.create()
dialogLoading.show()
Thread {
val password = edit_password.text.toString().toCharArray() val password = edit_password.text.toString().toCharArray()
val passwordConfirm = edit_password_confirm.text.toString().toCharArray() val passwordConfirm = edit_password_confirm.text.toString().toCharArray()
if (!password.contentEquals(passwordConfirm)) { if (!password.contentEquals(passwordConfirm)) {
dialogLoading.dismiss() stopTaskWithToast(R.string.passwords_mismatch)
toastFromThread(R.string.passwords_mismatch)
} else { } else {
rootCipherDir = edit_volume_path.text.toString() rootCipherDir = edit_volume_path.text.toString()
val volumePathFile = File(rootCipherDir) val volumePathFile = File(rootCipherDir)
@ -87,8 +75,7 @@ class CreateActivity : BaseActivity() {
if (volumePathFile.mkdirs()) { if (volumePathFile.mkdirs()) {
goodDirectory = true goodDirectory = true
} else { } else {
dialogLoading.dismiss() stopTaskWithToast(R.string.error_mkdir)
toastFromThread(R.string.error_mkdir)
} }
} else { } else {
val dirContent = volumePathFile.list() val dirContent = volumePathFile.list()
@ -96,12 +83,10 @@ class CreateActivity : BaseActivity() {
if (dirContent.isEmpty()) { if (dirContent.isEmpty()) {
goodDirectory = true goodDirectory = true
} else { } else {
dialogLoading.dismiss() stopTaskWithToast(R.string.dir_not_empty)
toastFromThread(R.string.dir_not_empty)
} }
} else { } else {
dialogLoading.dismiss() stopTaskWithToast(R.string.listdir_null_error_msg)
toastFromThread(R.string.listdir_null_error_msg)
} }
} }
if (goodDirectory) { if (goodDirectory) {
@ -127,25 +112,21 @@ class CreateActivity : BaseActivity() {
} }
editor.apply() editor.apply()
if (checkbox_save_password.isChecked && returnedHash != null){ if (checkbox_save_password.isChecked && returnedHash != null){
dialogLoading.dismiss()
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir){ _ -> fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir){ _ ->
runOnUiThread { startExplorer() } stopTask { startExplorer() }
} }
startExplorerImmediately = false startExplorerImmediately = false
} }
} }
if (startExplorerImmediately){ if (startExplorerImmediately){
dialogLoading.dismiss() stopTask { startExplorer() }
runOnUiThread { startExplorer() }
} }
} else { } else {
dialogLoading.dismiss() stopTaskWithToast(R.string.open_volume_failed)
toastFromThread(R.string.open_volume_failed)
} }
} else { } else {
dialogLoading.dismiss() stopTask {
runOnUiThread { ColoredAlertDialogBuilder(activity)
ColoredAlertDialogBuilder(this)
.setTitle(R.string.error) .setTitle(R.string.error)
.setMessage(R.string.create_volume_failed) .setMessage(R.string.create_volume_failed)
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
@ -156,7 +137,8 @@ class CreateActivity : BaseActivity() {
} }
Arrays.fill(password, 0.toChar()) Arrays.fill(password, 0.toChar())
Arrays.fill(passwordConfirm, 0.toChar()) Arrays.fill(passwordConfirm, 0.toChar())
}.start() }
}
} }
private fun startExplorer(){ private fun startExplorer(){

View File

@ -7,6 +7,8 @@ import android.os.Bundle
import android.view.View import android.view.View
import android.widget.AdapterView.OnItemClickListener import android.widget.AdapterView.OnItemClickListener
import android.widget.TextView import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_open.checkbox_remember_path import kotlinx.android.synthetic.main.activity_open.checkbox_remember_path
import kotlinx.android.synthetic.main.activity_open.checkbox_save_password import kotlinx.android.synthetic.main.activity_open.checkbox_save_password
import kotlinx.android.synthetic.main.activity_open.edit_password import kotlinx.android.synthetic.main.activity_open.edit_password
@ -18,10 +20,7 @@ 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.fingerprint_stuff.FingerprintPasswordHashSaver import sushi.hardcore.droidfs.fingerprint_stuff.FingerprintPasswordHashSaver
import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.util.*
import sushi.hardcore.droidfs.util.GocryptfsVolume
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.*
@ -83,20 +82,11 @@ class OpenActivity : BaseActivity() {
} }
fun onClickOpen(view: View?) { fun onClickOpen(view: View?) {
val dialogLoadingView = layoutInflater.inflate(R.layout.dialog_loading, null) object : LoadingTask(this, R.string.loading_msg_open){
val dialogTextMessage = dialogLoadingView.findViewById<TextView>(R.id.text_message) override fun doTask(activity: AppCompatActivity) {
dialogTextMessage.text = getString(R.string.loading_msg_open)
val dialogLoading = ColoredAlertDialogBuilder(this)
.setView(dialogLoadingView)
.setTitle(R.string.loading)
.setCancelable(false)
.create()
dialogLoading.show()
Thread {
rootCipherDir = edit_volume_path.text.toString() //fresh get in case of manual rewrite rootCipherDir = edit_volume_path.text.toString() //fresh get in case of manual rewrite
if (rootCipherDir.isEmpty()) { if (rootCipherDir.isEmpty()) {
dialogLoading.dismiss() stopTaskWithToast(R.string.enter_volume_path)
toastFromThread(R.string.enter_volume_path)
} else { } else {
val password = edit_password.text.toString().toCharArray() val password = edit_password.text.toString().toCharArray()
var returnedHash: ByteArray? = null var returnedHash: ByteArray? = null
@ -109,23 +99,18 @@ class OpenActivity : BaseActivity() {
if (checkbox_remember_path.isChecked) { if (checkbox_remember_path.isChecked) {
savedVolumesAdapter.addVolumePath(rootCipherDir) savedVolumesAdapter.addVolumePath(rootCipherDir)
if (checkbox_save_password.isChecked && returnedHash != null){ if (checkbox_save_password.isChecked && returnedHash != null){
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir) { success -> fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir) { _ ->
dialogLoading.dismiss() stopTask { startExplorer() }
if (success){
startExplorer()
}
} }
startExplorerImmediately = false startExplorerImmediately = false
} }
} }
if (startExplorerImmediately){ if (startExplorerImmediately){
dialogLoading.dismiss() stopTask { startExplorer() }
startExplorer()
} }
} else { } else {
dialogLoading.dismiss() stopTask {
runOnUiThread { ColoredAlertDialogBuilder(activity)
ColoredAlertDialogBuilder(this)
.setTitle(R.string.open_volume_failed) .setTitle(R.string.open_volume_failed)
.setMessage(R.string.open_volume_failed_msg) .setMessage(R.string.open_volume_failed_msg)
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
@ -134,22 +119,29 @@ class OpenActivity : BaseActivity() {
} }
Arrays.fill(password, 0.toChar()) Arrays.fill(password, 0.toChar())
} }
}.start() }
}
} }
private fun openUsingPasswordHash(passwordHash: ByteArray){ private fun openUsingPasswordHash(passwordHash: ByteArray){
object : LoadingTask(this, R.string.loading_msg_open){
override fun doTask(activity: AppCompatActivity) {
sessionID = GocryptfsVolume.init(rootCipherDir, null, passwordHash, null) sessionID = GocryptfsVolume.init(rootCipherDir, null, passwordHash, null)
if (sessionID != -1){ if (sessionID != -1){
startExplorer() stopTask { startExplorer() }
} else { } else {
ColoredAlertDialogBuilder(this) stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.open_volume_failed) .setTitle(R.string.open_volume_failed)
.setMessage(R.string.open_failed_hash_msg) .setMessage(R.string.open_failed_hash_msg)
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.show() .show()
} }
}
Arrays.fill(passwordHash, 0) Arrays.fill(passwordHash, 0)
} }
}
}
private fun startExplorer() { private fun startExplorer() {
var explorerIntent: Intent? = null var explorerIntent: Intent? = null

View File

@ -133,6 +133,11 @@ open class BaseExplorerActivity : BaseActivity() {
invalidateOptionsMenu() invalidateOptionsMenu()
} }
protected fun unselectAll(){
explorerAdapter.unSelectAll()
invalidateOptionsMenu()
}
private fun sortExplorerElements() { private fun sortExplorerElements() {
when (sortModesValues[currentSortModeIndex]) { when (sortModesValues[currentSortModeIndex]) {
"name" -> { "name" -> {
@ -199,8 +204,7 @@ open class BaseExplorerActivity : BaseActivity() {
setCurrentPath(PathUtils.get_parent_path(currentDirectoryPath)) setCurrentPath(PathUtils.get_parent_path(currentDirectoryPath))
} }
} else { } else {
explorerAdapter.unSelectAll() unselectAll()
invalidateOptionsMenu()
} }
} }
@ -287,8 +291,7 @@ open class BaseExplorerActivity : BaseActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) { return when (item.itemId) {
android.R.id.home -> { android.R.id.home -> {
explorerAdapter.unSelectAll() unselectAll()
invalidateOptionsMenu()
true true
} }
R.id.explorer_menu_sort -> { R.id.explorer_menu_sort -> {
@ -331,8 +334,7 @@ open class BaseExplorerActivity : BaseActivity() {
R.id.explorer_menu_external_open -> { R.id.explorer_menu_external_open -> {
if (usf_open){ if (usf_open){
ExternalProvider.open(this, gocryptfsVolume, PathUtils.path_join(currentDirectoryPath, explorerElements[explorerAdapter.selectedItems[0]].name)) ExternalProvider.open(this, gocryptfsVolume, PathUtils.path_join(currentDirectoryPath, explorerElements[explorerAdapter.selectedItems[0]].name))
explorerAdapter.unSelectAll() unselectAll()
invalidateOptionsMenu()
} }
true true
} }

View File

@ -8,15 +8,14 @@ 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.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.github.clans.fab.FloatingActionMenu import com.github.clans.fab.FloatingActionMenu
import kotlinx.android.synthetic.main.activity_explorer.* import kotlinx.android.synthetic.main.activity_explorer.*
import sushi.hardcore.droidfs.OpenActivity import sushi.hardcore.droidfs.OpenActivity
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.util.ExternalProvider import sushi.hardcore.droidfs.util.*
import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.util.GocryptfsVolume
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.*
@ -77,7 +76,7 @@ class ExplorerActivity : BaseExplorerActivity() {
fun onClickAddFile(view: View?) { fun onClickAddFile(view: View?) {
fam_explorer.close(true) fam_explorer.close(true)
val i = Intent(Intent.ACTION_GET_CONTENT) val i = Intent(Intent.ACTION_OPEN_DOCUMENT)
i.type = "*/*" i.type = "*/*"
i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true) i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
i.addCategory(Intent.CATEGORY_OPENABLE) i.addCategory(Intent.CATEGORY_OPENABLE)
@ -95,6 +94,8 @@ class ExplorerActivity : BaseExplorerActivity() {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (requestCode == PICK_FILES_REQUEST_CODE) { if (requestCode == PICK_FILES_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
object : LoadingTask(this, R.string.loading_msg_import){
override fun doTask(activity: AppCompatActivity) {
val uris: MutableList<Uri> = ArrayList() val uris: MutableList<Uri> = ArrayList()
val singleUri = data.data val singleUri = data.data
if (singleUri == null) { //multiples choices if (singleUri == null) { //multiples choices
@ -107,60 +108,77 @@ class ExplorerActivity : BaseExplorerActivity() {
} else { } else {
uris.add(singleUri) uris.add(singleUri)
} }
if (uris.isNotEmpty()){
var success = true var success = true
for (uri in uris) { for (uri in uris) {
val dstPath = PathUtils.path_join(currentDirectoryPath, PathUtils.getFilenameFromURI(this, uri)) val dstPath = PathUtils.path_join(currentDirectoryPath, PathUtils.getFilenameFromURI(activity, uri))
contentResolver.openInputStream(uri)?.let { contentResolver.openInputStream(uri)?.let {
success = gocryptfsVolume.import_file(it, dstPath) success = gocryptfsVolume.import_file(it, dstPath)
} }
if (!success) { if (!success) {
ColoredAlertDialogBuilder(this) stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.error) .setTitle(R.string.error)
.setMessage(getString(R.string.import_failed, uri)) .setMessage(getString(R.string.import_failed, uri))
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.show() .show()
}
break break
} }
} }
if (success) { if (success) {
ColoredAlertDialogBuilder(this) stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.success_import) .setTitle(R.string.success_import)
.setMessage(""" .setMessage("""
${getString(R.string.success_import_msg)} ${getString(R.string.success_import_msg)}
${getString(R.string.ask_for_wipe)} ${getString(R.string.ask_for_wipe)}
""".trimIndent()) """.trimIndent())
.setPositiveButton(R.string.yes) { _, _ -> .setPositiveButton(R.string.yes) { _, _ ->
object : LoadingTask(activity, R.string.loading_msg_wipe){
override fun doTask(activity: AppCompatActivity) {
success = true success = true
for (uri in uris) { for (uri in uris) {
if (!Wiper.wipe(this, uri)) { val errorMsg = Wiper.wipe(activity, uri)
ColoredAlertDialogBuilder(this) if (errorMsg != null) {
stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.error) .setTitle(R.string.error)
.setMessage(getString(R.string.wipe_failed, uri)) .setMessage(getString(R.string.wipe_failed, errorMsg))
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.show() .show()
}
success = false success = false
break break
} }
} }
if (success) { if (success) {
ColoredAlertDialogBuilder(this) stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.wipe_successful) .setTitle(R.string.wipe_successful)
.setMessage(R.string.wipe_success_msg) .setMessage(R.string.wipe_success_msg)
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.show() .show()
} }
} }
}
}
}
.setNegativeButton(getString(R.string.no), null) .setNegativeButton(getString(R.string.no), null)
.show() .show()
} }
}
}
override fun doFinally(activity: AppCompatActivity){
setCurrentPath(currentDirectoryPath) setCurrentPath(currentDirectoryPath)
} }
} }
}
} else if (requestCode == PICK_DIRECTORY_REQUEST_CODE) { } else if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
object : LoadingTask(this, R.string.loading_msg_export){
override fun doTask(activity: AppCompatActivity) {
val uri = data.data val uri = data.data
val outputDir = PathUtils.getFullPathFromTreeUri(uri, this) val outputDir = PathUtils.getFullPathFromTreeUri(uri, activity)
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)
@ -171,26 +189,35 @@ class ExplorerActivity : BaseExplorerActivity() {
if (gocryptfsVolume.export_file(fullPath, PathUtils.path_join(outputDir, element.name))) null else fullPath if (gocryptfsVolume.export_file(fullPath, PathUtils.path_join(outputDir, element.name))) null else fullPath
} }
if (failedItem != null) { if (failedItem != null) {
ColoredAlertDialogBuilder(this) stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.error) .setTitle(R.string.error)
.setMessage(getString(R.string.export_failed, failedItem)) .setMessage(getString(R.string.export_failed, failedItem))
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.show() .show()
}
break break
} }
} }
if (failedItem == null) { if (failedItem == null) {
ColoredAlertDialogBuilder(this) stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.success_export) .setTitle(R.string.success_export)
.setMessage(R.string.success_export_msg) .setMessage(R.string.success_export_msg)
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.show() .show()
} }
} }
explorerAdapter.unSelectAll() }
invalidateOptionsMenu() override fun doFinally(activity: AppCompatActivity) {
unselectAll()
}
}
}
} else if (requestCode == PICK_OTHER_VOLUME_ITEMS_REQUEST_CODE) { } else if (requestCode == PICK_OTHER_VOLUME_ITEMS_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
object : LoadingTask(this, R.string.loading_msg_import){
override fun doTask(activity: AppCompatActivity) {
val remoteSessionID = data.getIntExtra("sessionID", -1) val remoteSessionID = data.getIntExtra("sessionID", -1)
val remoteGocryptfsVolume = GocryptfsVolume(remoteSessionID) val remoteGocryptfsVolume = GocryptfsVolume(remoteSessionID)
val path = data.getStringExtra("path") val path = data.getStringExtra("path")
@ -214,23 +241,31 @@ class ExplorerActivity : BaseExplorerActivity() {
failedItem = if (importFileFromOtherVolume(remoteGocryptfsVolume, path, currentDirectoryPath)) null else path failedItem = if (importFileFromOtherVolume(remoteGocryptfsVolume, path, currentDirectoryPath)) null else path
} }
if (failedItem == null) { if (failedItem == null) {
ColoredAlertDialogBuilder(this) stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.success_import) .setTitle(R.string.success_import)
.setMessage(R.string.success_import_msg) .setMessage(R.string.success_import_msg)
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.show() .show()
}
} else { } else {
ColoredAlertDialogBuilder(this) stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.error) .setTitle(R.string.error)
.setMessage(getString(R.string.import_failed, failedItem)) .setMessage(getString(R.string.import_failed, failedItem))
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.show() .show()
} }
}
remoteGocryptfsVolume.close() remoteGocryptfsVolume.close()
}
override fun doFinally(activity: AppCompatActivity) {
setCurrentPath(currentDirectoryPath) setCurrentPath(currentDirectoryPath)
} }
} }
} }
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.explorer, menu) menuInflater.inflate(R.menu.explorer, menu)
@ -285,8 +320,7 @@ class ExplorerActivity : BaseExplorerActivity() {
paths.add(PathUtils.path_join(currentDirectoryPath, e.name)) paths.add(PathUtils.path_join(currentDirectoryPath, e.name))
} }
ExternalProvider.share(this, gocryptfsVolume, paths) ExternalProvider.share(this, gocryptfsVolume, paths)
explorerAdapter.unSelectAll() unselectAll()
invalidateOptionsMenu()
true true
} }
R.id.explorer_menu_decrypt -> { R.id.explorer_menu_decrypt -> {
@ -407,8 +441,7 @@ class ExplorerActivity : BaseExplorerActivity() {
break break
} }
} }
explorerAdapter.unSelectAll() unselectAll()
invalidateOptionsMenu()
setCurrentPath(currentDirectoryPath) //refresh setCurrentPath(currentDirectoryPath) //refresh
} }
} }

View File

@ -1,33 +0,0 @@
package sushi.hardcore.droidfs.fingerprint_stuff
import android.content.Context
import android.hardware.fingerprint.FingerprintManager
import android.os.Build
import android.os.CancellationSignal
import android.util.Log
import android.widget.Toast
import androidx.annotation.RequiresApi
@RequiresApi(Build.VERSION_CODES.M)
class FingerprintHandler(private val context: Context) : FingerprintManager.AuthenticationCallback(){
private lateinit var cancellationSignal: CancellationSignal
private lateinit var onTouched: (resultCode: onTouchedResultCodes) -> Unit
fun startAuth(fingerprintManager: FingerprintManager, cryptoObject: FingerprintManager.CryptoObject, onTouched: (resultCode: onTouchedResultCodes) -> Unit){
cancellationSignal = CancellationSignal()
this.onTouched = onTouched
fingerprintManager.authenticate(cryptoObject, cancellationSignal, 0, this, null)
}
override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult?) {
onTouched(onTouchedResultCodes.SUCCEED)
}
override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {
onTouched(onTouchedResultCodes.ERROR)
}
override fun onAuthenticationFailed() {
onTouched(onTouchedResultCodes.FAILED)
}
}

View File

@ -1,7 +0,0 @@
package sushi.hardcore.droidfs.fingerprint_stuff
enum class onTouchedResultCodes {
SUCCEED,
FAILED,
ERROR
}

View File

@ -3,12 +3,14 @@ package sushi.hardcore.droidfs.util
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.provider.RestrictedFileProvider import sushi.hardcore.droidfs.provider.RestrictedFileProvider
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
import java.io.File import java.io.File
import java.net.URLConnection import java.net.URLConnection
import java.util.* import java.util.*
import kotlin.collections.ArrayList
object ExternalProvider { object ExternalProvider {
private const val content_type_all = "*/*" private const val content_type_all = "*/*"
@ -37,23 +39,27 @@ object ExternalProvider {
return Pair(tmpFileUri, getContentType(fileName, previous_content_type)) return Pair(tmpFileUri, getContentType(fileName, previous_content_type))
} }
} }
ColoredAlertDialogBuilder(context)
.setTitle(R.string.error)
.setMessage(context.getString(R.string.export_failed, file_path))
.setPositiveButton(R.string.ok, null)
.show()
return Pair(null, null) return Pair(null, null)
} }
fun share(context: Context, gocryptfsVolume: GocryptfsVolume, file_paths: List<String>) { fun share(activity: AppCompatActivity, gocryptfsVolume: GocryptfsVolume, file_paths: List<String>) {
object : LoadingTask(activity, R.string.loading_msg_export){
override fun doTask(activity: AppCompatActivity) {
var contentType: String? = null var contentType: String? = null
val uris = ArrayList<Uri>() val uris = ArrayList<Uri>()
for (path in file_paths) { for (path in file_paths) {
val result = exportFile(context, gocryptfsVolume, path, contentType) val result = exportFile(activity, gocryptfsVolume, path, contentType)
contentType = if (result.first != null) { contentType = if (result.first != null) {
uris.add(result.first!!) uris.add(result.first!!)
result.second result.second
} else { } else {
stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.error)
.setMessage(activity.getString(R.string.export_failed, path))
.setPositiveButton(R.string.ok, null)
.show()
}
return return
} }
} }
@ -66,26 +72,45 @@ object ExternalProvider {
shareIntent.action = Intent.ACTION_SEND_MULTIPLE shareIntent.action = Intent.ACTION_SEND_MULTIPLE
shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris) shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
} }
context.startActivity(Intent.createChooser(shareIntent, context.getString(R.string.share_chooser))) stopTask {
activity.startActivity(Intent.createChooser(shareIntent, activity.getString(R.string.share_chooser)))
}
}
}
} }
fun open(context: Context, gocryptfsVolume: GocryptfsVolume, file_path: String) { fun open(activity: AppCompatActivity, gocryptfsVolume: GocryptfsVolume, file_path: String) {
val result = exportFile(context, gocryptfsVolume, file_path, null) object : LoadingTask(activity, R.string.loading_msg_export) {
result.first?.let { override fun doTask(activity: AppCompatActivity) {
val openIntent = Intent() val result = exportFile(activity, gocryptfsVolume, file_path, null)
openIntent.action = Intent.ACTION_VIEW if (result.first != null) {
val openIntent = Intent(Intent.ACTION_VIEW)
openIntent.setDataAndType(result.first, result.second) openIntent.setDataAndType(result.first, result.second)
context.startActivity(openIntent) stopTask { activity.startActivity(openIntent) }
} else {
stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.error)
.setMessage(activity.getString(R.string.export_failed, file_path))
.setPositiveButton(R.string.ok, null)
.show()
}
}
}
} }
} }
fun removeFiles(context: Context) { fun removeFiles(context: Context) {
Thread{ Thread{
val wiped = ArrayList<Uri>()
for (uri in storedFiles) { for (uri in storedFiles) {
if (Wiper.wipe(context, uri)){ if (Wiper.wipe(context, uri) == null){
storedFiles.remove(uri) wiped.add(uri)
} }
} }
for (uri in wiped){
storedFiles.remove(uri)
}
}.start() }.start()
} }
} }

View File

@ -0,0 +1,39 @@
package sushi.hardcore.droidfs.util
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
abstract class LoadingTask(private val activity: AppCompatActivity, private val loadingMessageResId: Int) {
private val dialogLoadingView = activity.layoutInflater.inflate(R.layout.dialog_loading, null)
private val dialogLoading: AlertDialog = ColoredAlertDialogBuilder(activity)
.setView(dialogLoadingView)
.setTitle(R.string.loading)
.setCancelable(false)
.create()
init {
dialogLoadingView.findViewById<TextView>(R.id.text_message).text = activity.getString(loadingMessageResId)
startTask()
}
abstract fun doTask(activity: AppCompatActivity)
open fun doFinally(activity: AppCompatActivity){}
private fun startTask() {
dialogLoading.show()
Thread {
doTask(activity)
activity.runOnUiThread { doFinally(activity) }
}.start()
}
protected fun stopTask(onUiThread: () -> Unit){
dialogLoading.dismiss()
activity.runOnUiThread {
onUiThread()
}
}
protected fun stopTaskWithToast(stringId: Int){
stopTask { Toast.makeText(activity, stringId, Toast.LENGTH_SHORT).show() }
}
}

View File

@ -4,7 +4,8 @@ import android.content.Context
import android.net.Uri import android.net.Uri
import android.provider.OpenableColumns import android.provider.OpenableColumns
import android.widget.EditText import android.widget.EditText
import sushi.hardcore.droidfs.ConstValues.Companion.wipe_passes import sushi.hardcore.droidfs.ConstValues
import sushi.hardcore.droidfs.R
import java.io.* import java.io.*
import java.lang.Exception import java.lang.Exception
import java.lang.StringBuilder import java.lang.StringBuilder
@ -14,7 +15,7 @@ import kotlin.math.ceil
object Wiper { object Wiper {
private const val buff_size = 4096 private const val buff_size = 4096
fun wipe(context: Context, uri: Uri): Boolean { fun wipe(context: Context, uri: Uri): String? {
val cursor = context.contentResolver.query(uri, null, null, null, null) val cursor = context.contentResolver.query(uri, null, null, null, null)
cursor?.let { cursor?.let {
val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE) val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
@ -26,11 +27,11 @@ object Wiper {
val buff = ByteArray(buff_size) val buff = ByteArray(buff_size)
Arrays.fill(buff, 0.toByte()) Arrays.fill(buff, 0.toByte())
val writes = ceil(size.toDouble() / buff_size).toInt() val writes = ceil(size.toDouble() / buff_size).toInt()
for (i in 0 until wipe_passes) { for (i in 0 until ConstValues.wipe_passes) {
for (j in 0 until writes) { for (j in 0 until writes) {
os!!.write(buff) os!!.write(buff)
} }
if (i < wipe_passes - 1) { if (i < ConstValues.wipe_passes - 1) {
//reopening to flush and seek //reopening to flush and seek
os!!.close() os!!.close()
os = context.contentResolver.openOutputStream(uri) os = context.contentResolver.openOutputStream(uri)
@ -42,26 +43,25 @@ object Wiper {
(os as FileOutputStream).channel.truncate(0) //truncate to 0 if cannot delete (os as FileOutputStream).channel.truncate(0) //truncate to 0 if cannot delete
} }
os!!.close() os!!.close()
return true return null
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() return e.message
} }
} }
return false return context.getString(R.string.query_cursor_null_error_msg)
} }
@JvmStatic fun wipe(file: File): String? {
fun wipe(file: File): Boolean{
val size = file.length() val size = file.length()
try { try {
var os = FileOutputStream(file) var os = FileOutputStream(file)
val buff = ByteArray(buff_size) val buff = ByteArray(buff_size)
Arrays.fill(buff, 0.toByte()) Arrays.fill(buff, 0.toByte())
val writes = ceil(size.toDouble() / buff_size).toInt() val writes = ceil(size.toDouble() / buff_size).toInt()
for (i in 0 until wipe_passes) { for (i in 0 until ConstValues.wipe_passes) {
for (j in 0 until writes) { for (j in 0 until writes) {
os.write(buff) os.write(buff)
} }
if (i < wipe_passes - 1) { if (i < ConstValues.wipe_passes - 1) {
//reopening to flush and seek //reopening to flush and seek
os.close() os.close()
os = FileOutputStream(file) os = FileOutputStream(file)
@ -73,10 +73,9 @@ object Wiper {
os.channel.truncate(0) //truncate to 0 if cannot delete os.channel.truncate(0) //truncate to 0 if cannot delete
} }
os.close() os.close()
return true return null
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() return e.message
return false
} }
} }
private fun randomString(minSize: Int, maxSize: Int): String { private fun randomString(minSize: Int, maxSize: Int): String {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -126,21 +126,22 @@
android:id="@+id/saved_path_listview" android:id="@+id/saved_path_listview"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="50dp" android:layout_marginHorizontal="@dimen/action_activity_listview_margin_horizontal"
android:layout_marginTop="20dp" android:layout_marginTop="@dimen/action_activity_listview_margin_top"
android:background="@drawable/listview_border"/> android:background="@drawable/listview_border"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="20dp" android:padding="@dimen/warning_msg_padding"
android:gravity="center" android:gravity="center"
android:text="@string/create_password_warning"/> android:text="@string/create_password_warning"/>
<Button <Button
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/action_activity_button_height" android:layout_height="@dimen/action_activity_button_height"
android:layout_marginHorizontal="@dimen/action_activity_button_hor_margin" android:layout_marginHorizontal="@dimen/action_activity_button_horizontal_margin"
android:layout_marginBottom="@dimen/action_activity_button_margin_bottom"
android:onClick="onClickChangePassword" android:onClick="onClickChangePassword"
android:text="@string/change_volume_password" android:text="@string/change_volume_password"
style="@style/button"/> style="@style/button"/>

View File

@ -105,14 +105,14 @@
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="20dp" android:padding="@dimen/warning_msg_padding"
android:gravity="center" android:gravity="center"
android:text="@string/create_password_warning"/> android:text="@string/create_password_warning"/>
<Button <Button
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/action_activity_button_height" android:layout_height="@dimen/action_activity_button_height"
android:layout_marginHorizontal="@dimen/action_activity_button_hor_margin" android:layout_marginHorizontal="@dimen/action_activity_button_horizontal_margin"
android:onClick="onClickCreate" android:onClick="onClickCreate"
android:text="@string/create_volume" android:text="@string/create_volume"
style="@style/button"/> style="@style/button"/>

View File

@ -86,20 +86,21 @@
android:id="@+id/saved_path_listview" android:id="@+id/saved_path_listview"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="50dp" android:layout_marginHorizontal="@dimen/action_activity_listview_margin_horizontal"
android:layout_marginTop="20dp"/> android:layout_marginTop="@dimen/action_activity_listview_margin_top"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="20dp" android:padding="@dimen/warning_msg_padding"
android:gravity="center" android:gravity="center"
android:text="@string/open_activity_warning"/> android:text="@string/open_activity_warning"/>
<Button <Button
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/action_activity_button_height" android:layout_height="@dimen/action_activity_button_height"
android:layout_marginHorizontal="@dimen/action_activity_button_hor_margin" android:layout_marginHorizontal="@dimen/action_activity_button_horizontal_margin"
android:layout_marginBottom="@dimen/action_activity_button_margin_bottom"
android:onClick="onClickOpen" android:onClick="onClickOpen"
android:text="@string/open_volume" android:text="@string/open_volume"
style="@style/button"/> style="@style/button"/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -7,7 +7,11 @@
<dimen name="edit_text_label_size">15sp</dimen> <dimen name="edit_text_label_size">15sp</dimen>
<dimen name="open_activity_label_width">90dp</dimen> <dimen name="open_activity_label_width">90dp</dimen>
<dimen name="change_password_activity_label_width">100dp</dimen> <dimen name="change_password_activity_label_width">100dp</dimen>
<dimen name="action_activity_button_hor_margin">60dp</dimen> <dimen name="action_activity_button_horizontal_margin">60dp</dimen>
<dimen name="action_activity_button_height">60dp</dimen> <dimen name="action_activity_button_height">60dp</dimen>
<dimen name="action_activity_listview_margin_horizontal">50dp</dimen>
<dimen name="action_activity_listview_margin_top">20dp</dimen>
<dimen name="warning_msg_padding">20dp</dimen>
<dimen name="action_activity_button_margin_bottom">20dp</dimen>
<dimen name="adapter_text_size">18sp</dimen> <dimen name="adapter_text_size">18sp</dimen>
</resources> </resources>

View File

@ -50,7 +50,7 @@
<string name="yes">YES</string> <string name="yes">YES</string>
<string name="no">NO</string> <string name="no">NO</string>
<string name="ask_for_wipe">Do you want to wipe the original files ?</string> <string name="ask_for_wipe">Do you want to wipe the original files ?</string>
<string name="wipe_failed">Wiping of %1$s failed</string> <string name="wipe_failed">Wiping failed: %1$s</string>
<string name="wipe_successful">Files successfully wiped !</string> <string name="wipe_successful">Files successfully wiped !</string>
<string name="wipe_success_msg">The imported files have been successfully wiped from their original locations.</string> <string name="wipe_success_msg">The imported files have been successfully wiped from their original locations.</string>
<string name="create_password_warning">Warning !\nThis password will be the only way to decrypt the volume and access the files inside.\nChoose a very strong password (not \"123456\" or \"password\"), do not lose it and keep it secure (preferably only in your mind).\n\nDroidFS cannot protect you from screen recording apps, keyloggers, apk backdooring, compromised root accesses, memory dumps etc.\nDo not type passwords in insecure environments.</string> <string name="create_password_warning">Warning !\nThis password will be the only way to decrypt the volume and access the files inside.\nChoose a very strong password (not \"123456\" or \"password\"), do not lose it and keep it secure (preferably only in your mind).\n\nDroidFS cannot protect you from screen recording apps, keyloggers, apk backdooring, compromised root accesses, memory dumps etc.\nDo not type passwords in insecure environments.</string>
@ -62,6 +62,7 @@
<string name="sort_order">Sort order:</string> <string name="sort_order">Sort order:</string>
<string name="old_password">Old password:</string> <string name="old_password">Old password:</string>
<string name="new_password">New password:</string> <string name="new_password">New password:</string>
<string name="new_password_confirmation">New Password (confirmation):</string>
<string name="success_change_password">Password successfully changed !</string> <string name="success_change_password">Password successfully changed !</string>
<string name="success_change_password_msg">The volume\'s password has been successfully changed.</string> <string name="success_change_password_msg">The volume\'s password has been successfully changed.</string>
<string name="change_password_failed">Failed to change the volume\'s password. Check the selected volume path and the entered old password.</string> <string name="change_password_failed">Failed to change the volume\'s password. Check the selected volume path and the entered old password.</string>
@ -118,12 +119,15 @@
<string name="discard">Discard</string> <string name="discard">Discard</string>
<string name="word_wrap">Word Wrap</string> <string name="word_wrap">Word Wrap</string>
<string name="outofmemoryerror_msg">OutOfMemoryError: This file is too large to be loaded in memory.</string> <string name="outofmemoryerror_msg">OutOfMemoryError: This file is too large to be loaded in memory.</string>
<string name="new_file">New File</string> <string name="new_file">Create New File</string>
<string name="enter_file_name">File name:</string> <string name="enter_file_name">File name:</string>
<string name="file_creation_failed">Failed to create the file.</string> <string name="file_creation_failed">Failed to create the file.</string>
<string name="loading">Loading...</string> <string name="loading">Loading…</string>
<string name="loading_msg_create">Creating volume...</string> <string name="loading_msg_create">Creating volume…</string>
<string name="loading_msg_change_password">Changing password...</string> <string name="loading_msg_change_password">Changing password…</string>
<string name="new_password_confirmation">New Password (confirmation):</string> <string name="loading_msg_open">Opening volume…</string>
<string name="loading_msg_open">Opening volume...</string> <string name="loading_msg_import">Importing selected files…</string>
<string name="loading_msg_wipe">Wiping original files…</string>
<string name="loading_msg_export">Exporting files…</string>
<string name="query_cursor_null_error_msg">Unable to access this file</string>
</resources> </resources>