Volume on SD cards warning
This commit is contained in:
parent
29b12898a4
commit
f44a702647
@ -20,6 +20,7 @@ import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter
|
||||
import sushi.hardcore.droidfs.fingerprint_stuff.FingerprintPasswordHashSaver
|
||||
import sushi.hardcore.droidfs.util.*
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class ChangePasswordActivity : BaseActivity() {
|
||||
@ -80,9 +81,25 @@ class ChangePasswordActivity : BaseActivity() {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
||||
if (data != null) {
|
||||
if (data?.data != null) {
|
||||
if (PathUtils.isTreeUriOnPrimaryStorage(data.data)){
|
||||
val path = PathUtils.getFullPathFromTreeUri(data.data, this)
|
||||
if (path != null){
|
||||
edit_volume_path.setText(path)
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.path_from_uri_null_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.change_pwd_on_sdcard_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,38 +109,53 @@ class ChangePasswordActivity : BaseActivity() {
|
||||
rootCipherDir = edit_volume_path.text.toString()
|
||||
if (rootCipherDir.isEmpty()) {
|
||||
Toast.makeText(this, R.string.enter_volume_path, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
if (!File(rootCipherDir).canWrite()){
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.change_pwd_cant_write_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
} else {
|
||||
changePassword(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun changePassword(givenHash: ByteArray?){
|
||||
object : LoadingTask(this, R.string.loading_msg_change_password){
|
||||
override fun doTask(activity: AppCompatActivity) {
|
||||
val newPassword = edit_new_password.text.toString().toCharArray()
|
||||
val newPasswordConfirm = edit_new_password_confirm.text.toString().toCharArray()
|
||||
if (!newPassword.contentEquals(newPasswordConfirm)) {
|
||||
stopTaskWithToast(R.string.passwords_mismatch)
|
||||
Toast.makeText(this, R.string.passwords_mismatch, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
object : LoadingTask(this, R.string.loading_msg_change_password) {
|
||||
override fun doTask(activity: AppCompatActivity) {
|
||||
val oldPassword = edit_old_password.text.toString().toCharArray()
|
||||
var returnedHash: ByteArray? = null
|
||||
if (usf_fingerprint && checkbox_save_password.isChecked){
|
||||
if (usf_fingerprint && checkbox_save_password.isChecked) {
|
||||
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
|
||||
}
|
||||
var changePasswordImmediately = true
|
||||
if (givenHash == null){
|
||||
if (givenHash == null) {
|
||||
val cipherText = sharedPrefs.getString(rootCipherDir, null)
|
||||
if (cipherText != null){ //password hash saved
|
||||
if (cipherText != null) { //password hash saved
|
||||
stopTask {
|
||||
fingerprintPasswordHashSaver.decrypt(cipherText, rootCipherDir, ::changePassword)
|
||||
}
|
||||
changePasswordImmediately = false
|
||||
}
|
||||
}
|
||||
if (changePasswordImmediately){
|
||||
if (GocryptfsVolume.changePassword(rootCipherDir, oldPassword, givenHash, newPassword, returnedHash)) {
|
||||
if (changePasswordImmediately) {
|
||||
if (GocryptfsVolume.changePassword(
|
||||
rootCipherDir,
|
||||
oldPassword,
|
||||
givenHash,
|
||||
newPassword,
|
||||
returnedHash
|
||||
)
|
||||
) {
|
||||
val editor = sharedPrefs.edit()
|
||||
if (sharedPrefs.getString(rootCipherDir, null) != null){
|
||||
if (sharedPrefs.getString(rootCipherDir, null) != null) {
|
||||
editor.remove(rootCipherDir)
|
||||
editor.apply()
|
||||
}
|
||||
@ -133,17 +165,20 @@ class ChangePasswordActivity : BaseActivity() {
|
||||
val newSavedVolumesPaths = oldSavedVolumesPaths.toMutableList()
|
||||
if (!oldSavedVolumesPaths.contains(rootCipherDir)) {
|
||||
newSavedVolumesPaths.add(rootCipherDir)
|
||||
editor.putStringSet(ConstValues.saved_volumes_key, newSavedVolumesPaths.toSet())
|
||||
editor.putStringSet(
|
||||
ConstValues.saved_volumes_key,
|
||||
newSavedVolumesPaths.toSet()
|
||||
)
|
||||
editor.apply()
|
||||
}
|
||||
if (checkbox_save_password.isChecked && returnedHash != null){
|
||||
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir){ _ ->
|
||||
if (checkbox_save_password.isChecked && returnedHash != null) {
|
||||
fingerprintPasswordHashSaver.encryptAndSave(returnedHash, rootCipherDir) { _ ->
|
||||
stopTask { onPasswordChanged() }
|
||||
}
|
||||
continueImmediately = false
|
||||
}
|
||||
}
|
||||
if (continueImmediately){
|
||||
if (continueImmediately) {
|
||||
stopTask { onPasswordChanged() }
|
||||
}
|
||||
} else {
|
||||
@ -158,11 +193,13 @@ class ChangePasswordActivity : BaseActivity() {
|
||||
}
|
||||
Arrays.fill(oldPassword, 0.toChar())
|
||||
}
|
||||
override fun doFinally(activity: AppCompatActivity) {
|
||||
Arrays.fill(newPassword, 0.toChar())
|
||||
Arrays.fill(newPasswordConfirm, 0.toChar())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onPasswordChanged(){
|
||||
ColoredAlertDialogBuilder(this)
|
||||
|
@ -5,12 +5,9 @@ import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
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_save_password
|
||||
import kotlinx.android.synthetic.main.activity_create.edit_password
|
||||
import kotlinx.android.synthetic.main.activity_create.edit_volume_path
|
||||
import kotlinx.android.synthetic.main.toolbar.*
|
||||
import sushi.hardcore.droidfs.explorers.ExplorerActivity
|
||||
import sushi.hardcore.droidfs.fingerprint_stuff.FingerprintPasswordHashSaver
|
||||
@ -19,6 +16,7 @@ import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
|
||||
class CreateActivity : BaseActivity() {
|
||||
companion object {
|
||||
private const val PICK_DIRECTORY_REQUEST_CODE = 1
|
||||
@ -53,36 +51,71 @@ class CreateActivity : BaseActivity() {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
||||
if (data != null) {
|
||||
if (data?.data != null) {
|
||||
if (PathUtils.isTreeUriOnPrimaryStorage(data.data)){
|
||||
val path = PathUtils.getFullPathFromTreeUri(data.data, this)
|
||||
if (path != null){
|
||||
edit_volume_path.setText(path)
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.path_from_uri_null_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.create_on_sdcard_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onClickCreate(view: View?) {
|
||||
object: LoadingTask(this, R.string.loading_msg_create){
|
||||
override fun doTask(activity: AppCompatActivity) {
|
||||
rootCipherDir = edit_volume_path.text.toString()
|
||||
if (rootCipherDir.isEmpty()) {
|
||||
Toast.makeText(this, R.string.enter_volume_path, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
val password = edit_password.text.toString().toCharArray()
|
||||
val passwordConfirm = edit_password_confirm.text.toString().toCharArray()
|
||||
if (!password.contentEquals(passwordConfirm)) {
|
||||
stopTaskWithToast(R.string.passwords_mismatch)
|
||||
Toast.makeText(this, R.string.passwords_mismatch, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
rootCipherDir = edit_volume_path.text.toString()
|
||||
object: LoadingTask(this, R.string.loading_msg_create){
|
||||
override fun doTask(activity: AppCompatActivity) {
|
||||
val volumePathFile = File(rootCipherDir)
|
||||
var goodDirectory = false
|
||||
if (!volumePathFile.isDirectory) {
|
||||
if (volumePathFile.mkdirs()) {
|
||||
goodDirectory = true
|
||||
} else {
|
||||
stopTaskWithToast(R.string.error_mkdir)
|
||||
stopTask {
|
||||
ColoredAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.create_cant_write_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val dirContent = volumePathFile.list()
|
||||
if (dirContent != null){
|
||||
if (dirContent.isEmpty()) {
|
||||
if (volumePathFile.canWrite()){
|
||||
goodDirectory = true
|
||||
} else {
|
||||
stopTask {
|
||||
ColoredAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.create_cant_write_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stopTaskWithToast(R.string.dir_not_empty)
|
||||
}
|
||||
@ -136,11 +169,14 @@ class CreateActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun doFinally(activity: AppCompatActivity) {
|
||||
Arrays.fill(password, 0.toChar())
|
||||
Arrays.fill(passwordConfirm, 0.toChar())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun startExplorer(){
|
||||
ColoredAlertDialogBuilder(this)
|
||||
|
@ -7,8 +7,16 @@ import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.AdapterView.OnItemClickListener
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import kotlinx.android.synthetic.main.activity_change_password.*
|
||||
import kotlinx.android.synthetic.main.activity_create.*
|
||||
import kotlinx.android.synthetic.main.activity_open.*
|
||||
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.edit_password
|
||||
import kotlinx.android.synthetic.main.activity_open.edit_volume_path
|
||||
import kotlinx.android.synthetic.main.activity_open.saved_path_listview
|
||||
import kotlinx.android.synthetic.main.toolbar.*
|
||||
import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter
|
||||
import sushi.hardcore.droidfs.explorers.ExplorerActivity
|
||||
@ -82,21 +90,51 @@ class OpenActivity : BaseActivity() {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
||||
if (data != null) {
|
||||
if (data?.data != null) {
|
||||
if (PathUtils.isTreeUriOnPrimaryStorage(data.data)){
|
||||
val path = PathUtils.getFullPathFromTreeUri(data.data, this)
|
||||
if (path != null){
|
||||
edit_volume_path.setText(path)
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.path_from_uri_null_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.open_on_sdcard_warning)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onClickOpen(view: View?) {
|
||||
rootCipherDir = edit_volume_path.text.toString()
|
||||
if (rootCipherDir.isEmpty()) {
|
||||
Toast.makeText(this, R.string.enter_volume_path, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
if (!File(rootCipherDir).canWrite()){
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.open_cant_write_warning)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.ok) { _, _ -> openVolume() }
|
||||
.show()
|
||||
} else {
|
||||
openVolume()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openVolume(){
|
||||
object : LoadingTask(this, R.string.loading_msg_open){
|
||||
override fun doTask(activity: AppCompatActivity) {
|
||||
rootCipherDir = edit_volume_path.text.toString() //fresh get in case of manual rewrite
|
||||
if (rootCipherDir.isEmpty()) {
|
||||
stopTaskWithToast(R.string.enter_volume_path)
|
||||
} else {
|
||||
val password = edit_password.text.toString().toCharArray()
|
||||
var returnedHash: ByteArray? = null
|
||||
if (usf_fingerprint && checkbox_save_password.isChecked){
|
||||
@ -130,7 +168,6 @@ class OpenActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openUsingPasswordHash(passwordHash: ByteArray){
|
||||
object : LoadingTask(this, R.string.loading_msg_open){
|
||||
|
@ -194,7 +194,9 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
total_size_text.text = getString(R.string.total_size, PathUtils.formatSize(totalSize))
|
||||
runOnUiThread {
|
||||
explorerAdapter.notifyDataSetChanged()
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,9 @@ import android.net.Uri;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.OpenableColumns;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
@ -81,24 +83,35 @@ public class PathUtils {
|
||||
return new DecimalFormat("#,##0.#").format(size/Math.pow(1024, digitGroups))+" "+units[digitGroups];
|
||||
}
|
||||
|
||||
public static Boolean isTreeUriOnPrimaryStorage(Uri treeUri){
|
||||
String volumeId = getVolumeIdFromTreeUri(treeUri);
|
||||
if (volumeId != null) {
|
||||
return volumeId.equals(PRIMARY_VOLUME_NAME) || volumeId.equals("home") || volumeId.equals("downloads");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String PRIMARY_VOLUME_NAME = "primary";
|
||||
@Nullable
|
||||
public static String getFullPathFromTreeUri(@Nullable final Uri treeUri, Context con) {
|
||||
public static String getFullPathFromTreeUri(@Nullable Uri treeUri, Context context) {
|
||||
if (treeUri == null) return null;
|
||||
String volumePath = getVolumePath(getVolumeIdFromTreeUri(treeUri),con);
|
||||
if (volumePath == null) return File.separator;
|
||||
if ("content".equalsIgnoreCase(treeUri.getScheme())) {
|
||||
String volumePath = getVolumePath(getVolumeIdFromTreeUri(treeUri),context);
|
||||
if (volumePath == null) return null;
|
||||
if (volumePath.endsWith(File.separator))
|
||||
volumePath = volumePath.substring(0, volumePath.length() - 1);
|
||||
String documentPath = getDocumentPathFromTreeUri(treeUri);
|
||||
if (documentPath.endsWith(File.separator))
|
||||
documentPath = documentPath.substring(0, documentPath.length() - 1);
|
||||
if (documentPath.length() > 0) {
|
||||
if (documentPath.startsWith(File.separator))
|
||||
return volumePath + documentPath;
|
||||
else
|
||||
return volumePath + File.separator + documentPath;
|
||||
return path_join(volumePath, documentPath);
|
||||
}
|
||||
else return volumePath;
|
||||
} else if ("file".equalsIgnoreCase(treeUri.getScheme())) {
|
||||
return treeUri.getPath();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getVolumePath(final String volumeId, Context context) {
|
||||
@ -117,7 +130,6 @@ public class PathUtils {
|
||||
Object storageVolumeElement = Array.get(result, i);
|
||||
String uuid = (String) getUuid.invoke(storageVolumeElement);
|
||||
Boolean primary = (Boolean) isPrimary.invoke(storageVolumeElement);
|
||||
|
||||
if (primary && PRIMARY_VOLUME_NAME.equals(volumeId))
|
||||
return (String) getPath.invoke(storageVolumeElement);
|
||||
if (uuid != null && uuid.equals(volumeId))
|
||||
|
@ -143,7 +143,7 @@
|
||||
android:layout_marginHorizontal="@dimen/action_activity_button_horizontal_margin"
|
||||
android:layout_marginBottom="@dimen/action_activity_button_margin_bottom"
|
||||
android:onClick="onClickChangePassword"
|
||||
android:text="@string/change_volume_password"
|
||||
android:text="@string/change_password"
|
||||
style="@style/button"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -114,7 +114,7 @@
|
||||
android:layout_height="@dimen/action_activity_button_height"
|
||||
android:layout_marginHorizontal="@dimen/action_activity_button_horizontal_margin"
|
||||
android:onClick="onClickCreate"
|
||||
android:text="@string/create_volume"
|
||||
android:text="@string/create"
|
||||
style="@style/button"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -102,7 +102,7 @@
|
||||
android:layout_marginHorizontal="@dimen/action_activity_button_horizontal_margin"
|
||||
android:layout_marginBottom="@dimen/action_activity_button_margin_bottom"
|
||||
android:onClick="onClickOpen"
|
||||
android:text="@string/open_volume"
|
||||
android:text="@string/open"
|
||||
style="@style/button"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -1,8 +1,11 @@
|
||||
<resources>
|
||||
<string name="app_name">DroidFS</string>
|
||||
<string name="open_volume">OPEN A VOLUME</string>
|
||||
<string name="create_volume">CREATE A VOLUME</string>
|
||||
<string name="change_volume_password">CHANGE VOLUME PASSWORD</string>
|
||||
<string name="open_volume">Open a volume</string>
|
||||
<string name="create_volume">Create a volume</string>
|
||||
<string name="change_volume_password">Change a volume\'s password</string>
|
||||
<string name="open">Open</string>
|
||||
<string name="create">Create</string>
|
||||
<string name="change_password">Change password</string>
|
||||
<string name="password">Password:</string>
|
||||
<string name="password_confirm">Password (confirmation):</string>
|
||||
<string name="volume_path">Volume Path:</string>
|
||||
@ -163,4 +166,11 @@
|
||||
<string name="choose_filter">Choose filter</string>
|
||||
<string name="filters_warning">Filters can only be applied to reduced quality images. If you want to take high definition photos, do not apply any filters.</string>
|
||||
<string name="timer_empty_error_msg">Please enter a numeric value</string>
|
||||
<string name="path_from_uri_null_error_msg">Failed to retrieve the selected path.</string>
|
||||
<string name="create_cant_write_error_msg">DroidFS doesn\'t have write access to this path. Please try another location.</string>
|
||||
<string name="create_on_sdcard_error_msg">DroidFS can\'t write on removable SD cards, please select a path on internal storage.</string>
|
||||
<string name="open_on_sdcard_warning">DroidFS can\'t write on removable SD cards. You will only have read-only access to the volumes therein.</string>
|
||||
<string name="open_cant_write_warning">DroidFS doesn\'t have write access to this path. You will only have read-only access to this volume.</string>
|
||||
<string name="change_pwd_cant_write_error_msg">DroidFS doesn\'t have write access to this path. You can try to move the volume to a writable location.</string>
|
||||
<string name="change_pwd_on_sdcard_error_msg">DroidFS can\'t write on removable SD cards, please move the volume to internal storage.</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user