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,80 +97,70 @@ 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 newPassword = edit_new_password.text.toString().toCharArray()
val dialogLoading = ColoredAlertDialogBuilder(this) val newPasswordConfirm = edit_new_password_confirm.text.toString().toCharArray()
.setView(dialogLoadingView) if (!newPassword.contentEquals(newPasswordConfirm)) {
.setTitle(R.string.loading) stopTaskWithToast(R.string.passwords_mismatch)
.setCancelable(false) } else {
.create() val oldPassword = edit_old_password.text.toString().toCharArray()
dialogLoading.show() var returnedHash: ByteArray? = null
Thread { if (usf_fingerprint && checkbox_save_password.isChecked){
val newPassword = edit_new_password.text.toString().toCharArray() returnedHash = ByteArray(GocryptfsVolume.KeyLen)
val newPasswordConfirm = edit_new_password_confirm.text.toString().toCharArray()
if (!newPassword.contentEquals(newPasswordConfirm)) {
dialogLoading.dismiss()
toastFromThread(R.string.passwords_mismatch)
} else {
val oldPassword = edit_old_password.text.toString().toCharArray()
var returnedHash: ByteArray? = null
if (usf_fingerprint && checkbox_save_password.isChecked){
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
}
var changePasswordImmediately = true
if (givenHash == null){
val cipherText = sharedPrefs.getString(rootCipherDir, null)
if (cipherText != null){ //password hash saved
dialogLoading.dismiss()
fingerprintPasswordHashSaver.decrypt(cipherText, rootCipherDir, ::changePassword)
changePasswordImmediately = false
} }
} var changePasswordImmediately = true
if (changePasswordImmediately){ if (givenHash == null){
if (GocryptfsVolume.change_password(rootCipherDir, oldPassword, givenHash, newPassword, returnedHash)) { val cipherText = sharedPrefs.getString(rootCipherDir, null)
val editor = sharedPrefs.edit() if (cipherText != null){ //password hash saved
if (sharedPrefs.getString(rootCipherDir, null) != null){ stopTask {
editor.remove(rootCipherDir) fingerprintPasswordHashSaver.decrypt(cipherText, rootCipherDir, ::changePassword)
editor.apply() }
changePasswordImmediately = false
} }
var continueImmediately = true }
if (checkbox_remember_path.isChecked) { if (changePasswordImmediately){
val oldSavedVolumesPaths = sharedPrefs.getStringSet(ConstValues.saved_volumes_key, HashSet()) as Set<String> if (GocryptfsVolume.change_password(rootCipherDir, oldPassword, givenHash, newPassword, returnedHash)) {
val newSavedVolumesPaths = oldSavedVolumesPaths.toMutableList() val editor = sharedPrefs.edit()
if (!oldSavedVolumesPaths.contains(rootCipherDir)) { if (sharedPrefs.getString(rootCipherDir, null) != null){
newSavedVolumesPaths.add(rootCipherDir) editor.remove(rootCipherDir)
editor.putStringSet(ConstValues.saved_volumes_key, newSavedVolumesPaths.toSet())
editor.apply() editor.apply()
} }
if (checkbox_save_password.isChecked && returnedHash != null){ var continueImmediately = true
dialogLoading.dismiss() if (checkbox_remember_path.isChecked) {
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir){ _ -> val oldSavedVolumesPaths = sharedPrefs.getStringSet(ConstValues.saved_volumes_key, HashSet()) as Set<String>
onPasswordChanged() val newSavedVolumesPaths = oldSavedVolumesPaths.toMutableList()
if (!oldSavedVolumesPaths.contains(rootCipherDir)) {
newSavedVolumesPaths.add(rootCipherDir)
editor.putStringSet(ConstValues.saved_volumes_key, newSavedVolumesPaths.toSet())
editor.apply()
} }
continueImmediately = false if (checkbox_save_password.isChecked && returnedHash != null){
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir){ _ ->
stopTask { onPasswordChanged() }
}
continueImmediately = false
}
}
if (continueImmediately){
stopTask { onPasswordChanged() }
}
} else {
stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.error)
.setMessage(R.string.change_password_failed)
.setPositiveButton(R.string.ok, null)
.show()
} }
} }
if (continueImmediately){
dialogLoading.dismiss()
runOnUiThread { onPasswordChanged() }
}
} else {
dialogLoading.dismiss()
runOnUiThread {
ColoredAlertDialogBuilder(this)
.setTitle(R.string.error)
.setMessage(R.string.change_password_failed)
.setPositiveButton(R.string.ok, null)
.show()
}
} }
Arrays.fill(oldPassword, 0.toChar())
} }
Arrays.fill(oldPassword, 0.toChar()) Arrays.fill(newPassword, 0.toChar())
Arrays.fill(newPasswordConfirm, 0.toChar())
} }
Arrays.fill(newPassword, 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,99 +61,84 @@ 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 password = edit_password.text.toString().toCharArray()
val dialogLoading = ColoredAlertDialogBuilder(this) val passwordConfirm = edit_password_confirm.text.toString().toCharArray()
.setView(dialogLoadingView) if (!password.contentEquals(passwordConfirm)) {
.setTitle(R.string.loading) stopTaskWithToast(R.string.passwords_mismatch)
.setCancelable(false)
.create()
dialogLoading.show()
Thread {
val password = edit_password.text.toString().toCharArray()
val passwordConfirm = edit_password_confirm.text.toString().toCharArray()
if (!password.contentEquals(passwordConfirm)) {
dialogLoading.dismiss()
toastFromThread(R.string.passwords_mismatch)
} else {
rootCipherDir = edit_volume_path.text.toString()
val volumePathFile = File(rootCipherDir)
var goodDirectory = false
if (!volumePathFile.isDirectory) {
if (volumePathFile.mkdirs()) {
goodDirectory = true
} else {
dialogLoading.dismiss()
toastFromThread(R.string.error_mkdir)
}
} else { } else {
val dirContent = volumePathFile.list() rootCipherDir = edit_volume_path.text.toString()
if (dirContent != null){ val volumePathFile = File(rootCipherDir)
if (dirContent.isEmpty()) { var goodDirectory = false
if (!volumePathFile.isDirectory) {
if (volumePathFile.mkdirs()) {
goodDirectory = true goodDirectory = true
} else { } else {
dialogLoading.dismiss() stopTaskWithToast(R.string.error_mkdir)
toastFromThread(R.string.dir_not_empty)
} }
} else { } else {
dialogLoading.dismiss() val dirContent = volumePathFile.list()
toastFromThread(R.string.listdir_null_error_msg) if (dirContent != null){
} if (dirContent.isEmpty()) {
} goodDirectory = true
if (goodDirectory) { } else {
if (GocryptfsVolume.create_volume(rootCipherDir, password, GocryptfsVolume.ScryptDefaultLogN, ConstValues.creator)) { stopTaskWithToast(R.string.dir_not_empty)
var returnedHash: ByteArray? = null
if (usf_fingerprint && checkbox_save_password.isChecked){
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
}
sessionID = GocryptfsVolume.init(rootCipherDir, password, null, returnedHash)
if (sessionID != -1) {
var startExplorerImmediately = true
if (checkbox_remember_path.isChecked) {
val oldSavedVolumesPaths = sharedPrefs.getStringSet(ConstValues.saved_volumes_key, HashSet()) as Set<String>
val editor = sharedPrefs.edit()
val newSavedVolumesPaths = oldSavedVolumesPaths.toMutableList()
if (oldSavedVolumesPaths.contains(rootCipherDir)) {
if (sharedPrefs.getString(rootCipherDir, null) != null){
editor.remove(rootCipherDir)
}
} else {
newSavedVolumesPaths.add(rootCipherDir)
editor.putStringSet(ConstValues.saved_volumes_key, newSavedVolumesPaths.toSet())
}
editor.apply()
if (checkbox_save_password.isChecked && returnedHash != null){
dialogLoading.dismiss()
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir){ _ ->
runOnUiThread { startExplorer() }
}
startExplorerImmediately = false
}
}
if (startExplorerImmediately){
dialogLoading.dismiss()
runOnUiThread { startExplorer() }
} }
} else { } else {
dialogLoading.dismiss() stopTaskWithToast(R.string.listdir_null_error_msg)
toastFromThread(R.string.open_volume_failed)
} }
} else { }
dialogLoading.dismiss() if (goodDirectory) {
runOnUiThread { if (GocryptfsVolume.create_volume(rootCipherDir, password, GocryptfsVolume.ScryptDefaultLogN, ConstValues.creator)) {
ColoredAlertDialogBuilder(this) var returnedHash: ByteArray? = null
.setTitle(R.string.error) if (usf_fingerprint && checkbox_save_password.isChecked){
.setMessage(R.string.create_volume_failed) returnedHash = ByteArray(GocryptfsVolume.KeyLen)
.setPositiveButton(R.string.ok, null) }
.show() sessionID = GocryptfsVolume.init(rootCipherDir, password, null, returnedHash)
if (sessionID != -1) {
var startExplorerImmediately = true
if (checkbox_remember_path.isChecked) {
val oldSavedVolumesPaths = sharedPrefs.getStringSet(ConstValues.saved_volumes_key, HashSet()) as Set<String>
val editor = sharedPrefs.edit()
val newSavedVolumesPaths = oldSavedVolumesPaths.toMutableList()
if (oldSavedVolumesPaths.contains(rootCipherDir)) {
if (sharedPrefs.getString(rootCipherDir, null) != null){
editor.remove(rootCipherDir)
}
} else {
newSavedVolumesPaths.add(rootCipherDir)
editor.putStringSet(ConstValues.saved_volumes_key, newSavedVolumesPaths.toSet())
}
editor.apply()
if (checkbox_save_password.isChecked && returnedHash != null){
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir){ _ ->
stopTask { startExplorer() }
}
startExplorerImmediately = false
}
}
if (startExplorerImmediately){
stopTask { startExplorer() }
}
} else {
stopTaskWithToast(R.string.open_volume_failed)
}
} else {
stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.error)
.setMessage(R.string.create_volume_failed)
.setPositiveButton(R.string.ok, null)
.show()
}
} }
} }
} }
Arrays.fill(password, 0.toChar())
Arrays.fill(passwordConfirm, 0.toChar())
} }
Arrays.fill(password, 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,72 +82,65 @@ 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) rootCipherDir = edit_volume_path.text.toString() //fresh get in case of manual rewrite
val dialogLoading = ColoredAlertDialogBuilder(this) if (rootCipherDir.isEmpty()) {
.setView(dialogLoadingView) stopTaskWithToast(R.string.enter_volume_path)
.setTitle(R.string.loading) } else {
.setCancelable(false) val password = edit_password.text.toString().toCharArray()
.create() var returnedHash: ByteArray? = null
dialogLoading.show() if (usf_fingerprint && checkbox_save_password.isChecked){
Thread { returnedHash = ByteArray(GocryptfsVolume.KeyLen)
rootCipherDir = edit_volume_path.text.toString() //fresh get in case of manual rewrite }
if (rootCipherDir.isEmpty()) { sessionID = GocryptfsVolume.init(rootCipherDir, password, null, returnedHash)
dialogLoading.dismiss() if (sessionID != -1) {
toastFromThread(R.string.enter_volume_path) var startExplorerImmediately = true
} else { if (checkbox_remember_path.isChecked) {
val password = edit_password.text.toString().toCharArray() savedVolumesAdapter.addVolumePath(rootCipherDir)
var returnedHash: ByteArray? = null if (checkbox_save_password.isChecked && returnedHash != null){
if (usf_fingerprint && checkbox_save_password.isChecked){ fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir) { _ ->
returnedHash = ByteArray(GocryptfsVolume.KeyLen) stopTask { startExplorer() }
}
sessionID = GocryptfsVolume.init(rootCipherDir, password, null, returnedHash)
if (sessionID != -1) {
var startExplorerImmediately = true
if (checkbox_remember_path.isChecked) {
savedVolumesAdapter.addVolumePath(rootCipherDir)
if (checkbox_save_password.isChecked && returnedHash != null){
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir) { success ->
dialogLoading.dismiss()
if (success){
startExplorer()
} }
startExplorerImmediately = false
} }
startExplorerImmediately = false }
if (startExplorerImmediately){
stopTask { startExplorer() }
}
} else {
stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.open_volume_failed)
.setMessage(R.string.open_volume_failed_msg)
.setPositiveButton(R.string.ok, null)
.show()
} }
} }
if (startExplorerImmediately){ Arrays.fill(password, 0.toChar())
dialogLoading.dismiss() }
startExplorer() }
} }
}
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)
if (sessionID != -1){
stopTask { 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_failed_hash_msg)
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.show() .show()
} }
} }
Arrays.fill(password, 0.toChar()) Arrays.fill(passwordHash, 0)
} }
}.start()
}
private fun openUsingPasswordHash(passwordHash: ByteArray){
sessionID = GocryptfsVolume.init(rootCipherDir, null, passwordHash, null)
if (sessionID != -1){
startExplorer()
} else {
ColoredAlertDialogBuilder(this)
.setTitle(R.string.open_volume_failed)
.setMessage(R.string.open_failed_hash_msg)
.setPositiveButton(R.string.ok, null)
.show()
} }
Arrays.fill(passwordHash, 0)
} }
private fun startExplorer() { private fun startExplorer() {

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,139 +94,175 @@ 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) {
val uris: MutableList<Uri> = ArrayList() object : LoadingTask(this, R.string.loading_msg_import){
val singleUri = data.data override fun doTask(activity: AppCompatActivity) {
if (singleUri == null) { //multiples choices val uris: MutableList<Uri> = ArrayList()
val clipData = data.clipData val singleUri = data.data
if (clipData != null){ if (singleUri == null) { //multiples choices
for (i in 0 until clipData.itemCount) { val clipData = data.clipData
uris.add(clipData.getItemAt(i).uri) if (clipData != null){
for (i in 0 until clipData.itemCount) {
uris.add(clipData.getItemAt(i).uri)
}
}
} else {
uris.add(singleUri)
} }
} var success = true
} else { for (uri in uris) {
uris.add(singleUri) val dstPath = PathUtils.path_join(currentDirectoryPath, PathUtils.getFilenameFromURI(activity, uri))
} contentResolver.openInputStream(uri)?.let {
if (uris.isNotEmpty()){ success = gocryptfsVolume.import_file(it, dstPath)
var success = true }
for (uri in uris) { if (!success) {
val dstPath = PathUtils.path_join(currentDirectoryPath, PathUtils.getFilenameFromURI(this, uri)) stopTask {
contentResolver.openInputStream(uri)?.let { ColoredAlertDialogBuilder(activity)
success = gocryptfsVolume.import_file(it, dstPath) .setTitle(R.string.error)
.setMessage(getString(R.string.import_failed, uri))
.setPositiveButton(R.string.ok, null)
.show()
}
break
}
} }
if (!success) { if (success) {
ColoredAlertDialogBuilder(this) stopTask {
.setTitle(R.string.error) ColoredAlertDialogBuilder(activity)
.setMessage(getString(R.string.import_failed, uri)) .setTitle(R.string.success_import)
.setPositiveButton(R.string.ok, null) .setMessage("""
.show() ${getString(R.string.success_import_msg)}
break ${getString(R.string.ask_for_wipe)}
} """.trimIndent())
} .setPositiveButton(R.string.yes) { _, _ ->
if (success) { object : LoadingTask(activity, R.string.loading_msg_wipe){
ColoredAlertDialogBuilder(this) override fun doTask(activity: AppCompatActivity) {
.setTitle(R.string.success_import) success = true
.setMessage(""" for (uri in uris) {
${getString(R.string.success_import_msg)} val errorMsg = Wiper.wipe(activity, uri)
${getString(R.string.ask_for_wipe)} if (errorMsg != null) {
""".trimIndent()) stopTask {
.setPositiveButton(R.string.yes) { _, _ -> ColoredAlertDialogBuilder(activity)
success = true .setTitle(R.string.error)
for (uri in uris) { .setMessage(getString(R.string.wipe_failed, errorMsg))
if (!Wiper.wipe(this, uri)) { .setPositiveButton(R.string.ok, null)
ColoredAlertDialogBuilder(this) .show()
.setTitle(R.string.error) }
.setMessage(getString(R.string.wipe_failed, uri)) success = false
.setPositiveButton(R.string.ok, null) break
.show() }
success = false }
break if (success) {
stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.wipe_successful)
.setMessage(R.string.wipe_success_msg)
.setPositiveButton(R.string.ok, null)
.show()
}
}
}
} }
} }
if (success) { .setNegativeButton(getString(R.string.no), null)
ColoredAlertDialogBuilder(this) .show()
.setTitle(R.string.wipe_successful) }
.setMessage(R.string.wipe_success_msg) }
.setPositiveButton(R.string.ok, null) }
.show() override fun doFinally(activity: AppCompatActivity){
} setCurrentPath(currentDirectoryPath)
}
.setNegativeButton(getString(R.string.no), null)
.show()
} }
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) {
val uri = data.data object : LoadingTask(this, R.string.loading_msg_export){
val outputDir = PathUtils.getFullPathFromTreeUri(uri, this) override fun doTask(activity: AppCompatActivity) {
var failedItem: String? = null val uri = data.data
for (i in explorerAdapter.selectedItems) { val outputDir = PathUtils.getFullPathFromTreeUri(uri, activity)
val element = explorerAdapter.getItem(i) var failedItem: String? = null
val fullPath = PathUtils.path_join(currentDirectoryPath, element.name) for (i in explorerAdapter.selectedItems) {
failedItem = if (element.isDirectory) { val element = explorerAdapter.getItem(i)
recursiveExportDirectory(fullPath, outputDir) val fullPath = PathUtils.path_join(currentDirectoryPath, element.name)
} else { failedItem = if (element.isDirectory) {
if (gocryptfsVolume.export_file(fullPath, PathUtils.path_join(outputDir, element.name))) null else fullPath recursiveExportDirectory(fullPath, outputDir)
}
if (failedItem != null) {
ColoredAlertDialogBuilder(this)
.setTitle(R.string.error)
.setMessage(getString(R.string.export_failed, failedItem))
.setPositiveButton(R.string.ok, null)
.show()
break
}
}
if (failedItem == null) {
ColoredAlertDialogBuilder(this)
.setTitle(R.string.success_export)
.setMessage(R.string.success_export_msg)
.setPositiveButton(R.string.ok, null)
.show()
}
}
explorerAdapter.unSelectAll()
invalidateOptionsMenu()
} 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")
var failedItem: String? = null
if (path == null) {
val paths = data.getStringArrayListExtra("paths")
val types = data.getIntegerArrayListExtra("types")
if (types != null && paths != null){
for (i in paths.indices) {
failedItem = if (types[i] == 0) { //directory
recursiveImportDirectoryFromOtherVolume(remoteGocryptfsVolume, paths[i], currentDirectoryPath)
} else { } else {
if (importFileFromOtherVolume(remoteGocryptfsVolume, paths[i], currentDirectoryPath)) null else paths[i] if (gocryptfsVolume.export_file(fullPath, PathUtils.path_join(outputDir, element.name))) null else fullPath
} }
if (failedItem != null) { if (failedItem != null) {
stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.error)
.setMessage(getString(R.string.export_failed, failedItem))
.setPositiveButton(R.string.ok, null)
.show()
}
break break
} }
} }
if (failedItem == null) {
stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.success_export)
.setMessage(R.string.success_export_msg)
.setPositiveButton(R.string.ok, null)
.show()
}
}
}
override fun doFinally(activity: AppCompatActivity) {
unselectAll()
} }
} else {
failedItem = if (importFileFromOtherVolume(remoteGocryptfsVolume, path, currentDirectoryPath)) null else path
} }
if (failedItem == null) { }
ColoredAlertDialogBuilder(this) } else if (requestCode == PICK_OTHER_VOLUME_ITEMS_REQUEST_CODE) {
.setTitle(R.string.success_import) if (resultCode == Activity.RESULT_OK && data != null) {
.setMessage(R.string.success_import_msg) object : LoadingTask(this, R.string.loading_msg_import){
.setPositiveButton(R.string.ok, null) override fun doTask(activity: AppCompatActivity) {
.show() val remoteSessionID = data.getIntExtra("sessionID", -1)
} else { val remoteGocryptfsVolume = GocryptfsVolume(remoteSessionID)
ColoredAlertDialogBuilder(this) val path = data.getStringExtra("path")
.setTitle(R.string.error) var failedItem: String? = null
.setMessage(getString(R.string.import_failed, failedItem)) if (path == null) {
.setPositiveButton(R.string.ok, null) val paths = data.getStringArrayListExtra("paths")
.show() val types = data.getIntegerArrayListExtra("types")
if (types != null && paths != null){
for (i in paths.indices) {
failedItem = if (types[i] == 0) { //directory
recursiveImportDirectoryFromOtherVolume(remoteGocryptfsVolume, paths[i], currentDirectoryPath)
} else {
if (importFileFromOtherVolume(remoteGocryptfsVolume, paths[i], currentDirectoryPath)) null else paths[i]
}
if (failedItem != null) {
break
}
}
}
} else {
failedItem = if (importFileFromOtherVolume(remoteGocryptfsVolume, path, currentDirectoryPath)) null else path
}
if (failedItem == null) {
stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.success_import)
.setMessage(R.string.success_import_msg)
.setPositiveButton(R.string.ok, null)
.show()
}
} else {
stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.error)
.setMessage(getString(R.string.import_failed, failedItem))
.setPositiveButton(R.string.ok, null)
.show()
}
}
remoteGocryptfsVolume.close()
}
override fun doFinally(activity: AppCompatActivity) {
setCurrentPath(currentDirectoryPath)
}
} }
remoteGocryptfsVolume.close()
setCurrentPath(currentDirectoryPath)
} }
} }
} }
@ -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,55 +39,78 @@ 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>) {
var contentType: String? = null object : LoadingTask(activity, R.string.loading_msg_export){
val uris = ArrayList<Uri>() override fun doTask(activity: AppCompatActivity) {
for (path in file_paths) { var contentType: String? = null
val result = exportFile(context, gocryptfsVolume, path, contentType) val uris = ArrayList<Uri>()
contentType = if (result.first != null) { for (path in file_paths) {
uris.add(result.first!!) val result = exportFile(activity, gocryptfsVolume, path, contentType)
result.second contentType = if (result.first != null) {
} else { uris.add(result.first!!)
return result.second
} else {
stopTask {
ColoredAlertDialogBuilder(activity)
.setTitle(R.string.error)
.setMessage(activity.getString(R.string.export_failed, path))
.setPositiveButton(R.string.ok, null)
.show()
}
return
}
}
val shareIntent = Intent()
shareIntent.type = contentType
if (uris.size == 1) {
shareIntent.action = Intent.ACTION_SEND
shareIntent.putExtra(Intent.EXTRA_STREAM, uris[0])
} else {
shareIntent.action = Intent.ACTION_SEND_MULTIPLE
shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
}
stopTask {
activity.startActivity(Intent.createChooser(shareIntent, activity.getString(R.string.share_chooser)))
}
} }
} }
val shareIntent = Intent()
shareIntent.type = contentType
if (uris.size == 1) {
shareIntent.action = Intent.ACTION_SEND
shareIntent.putExtra(Intent.EXTRA_STREAM, uris[0])
} else {
shareIntent.action = Intent.ACTION_SEND_MULTIPLE
shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
}
context.startActivity(Intent.createChooser(shareIntent, context.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) {
openIntent.setDataAndType(result.first, result.second) val openIntent = Intent(Intent.ACTION_VIEW)
context.startActivity(openIntent) openIntent.setDataAndType(result.first, result.second)
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>