aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
diff options
context:
space:
mode:
authorHarsh Shandilya <msfjarvis@gmail.com>2020-07-03 12:54:06 +0530
committerGitHub <noreply@github.com>2020-07-03 09:24:06 +0200
commit25b426157417c97c61c3d2cc0d9fa556f337f22d (patch)
treef53331d7ee2d5b780ebf20a6ccdded53bda42005 /app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
parentff3d2fcce3f1d74bdb1e13e3634f1ea9a9f9f1e5 (diff)
downloadHardenedPass-25b426157417c97c61c3d2cc0d9fa556f337f22d.tar.gz
HardenedPass-25b426157417c97c61c3d2cc0d9fa556f337f22d.zip
Migrate to ActivityResultContracts (#910)
* Move git directory selection to ActivityResultContracts Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * global: replace all android.app.Activity references Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * res: resolve ObsoleteSdkInt lint warning Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * layout: silence some overdraw warnings Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * PasswordFragment: address deprecation Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * PasswordStore: start addressing deprecation warnings Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * autofill: silence deprecation warnings for legacy implementation I don't want to ever touch these files Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Reset scrollTarget after use Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Refresh password list after each swipe Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Convert if to when Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Migrate UserPreference to ActivityResultContracts Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Also validate result in git directory selection Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * AutofillSaveActivity: Switch to ActivityResultContracts Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * AutofillDecryptActivity: Switch to ActivityResultContracts Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * AutofillFilterActivity: Switch to ActivityResultContracts Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Improve deletion flow - Silently delete empty directory - Always refresh password list upon completion Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Uniform naming for activity result handlers Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> Co-authored-by: Fabian Henneke <FabianHenneke@users.noreply.github.com>
Diffstat (limited to 'app/src/main/java/com/zeapo/pwdstore/UserPreference.kt')
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/UserPreference.kt241
1 files changed, 116 insertions, 125 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
index 03e314f6..ea3bac38 100644
--- a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
@@ -6,7 +6,6 @@ package com.zeapo.pwdstore
import android.accessibilityservice.AccessibilityServiceInfo
import android.annotation.SuppressLint
-import android.app.Activity
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.ShortcutManager
@@ -21,7 +20,8 @@ import android.text.TextUtils
import android.view.MenuItem
import android.view.accessibility.AccessibilityManager
import android.widget.Toast
-import androidx.activity.result.contract.ActivityResultContracts
+import androidx.activity.result.ActivityResult
+import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatTextView
import androidx.biometric.BiometricManager
@@ -167,7 +167,7 @@ class UserPreference : AppCompatActivity() {
false
} else {
val intent = Intent(callingActivity, GetKeyIdsActivity::class.java)
- val keySelectResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
+ val keySelectResult = registerForActivityResult(StartActivityForResult()) {
updateKeyIDsSummary(pref)
}
keySelectResult.launch(intent)
@@ -490,7 +490,7 @@ class UserPreference : AppCompatActivity() {
override fun onBackPressed() {
super.onBackPressed()
- setResult(Activity.RESULT_OK)
+ setResult(RESULT_OK)
finish()
}
@@ -511,13 +511,40 @@ class UserPreference : AppCompatActivity() {
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
+ @Suppress("Deprecation") // for Environment.getExternalStorageDirectory()
fun selectExternalGitRepository() {
MaterialAlertDialogBuilder(this)
.setTitle(this.resources.getString(R.string.external_repository_dialog_title))
.setMessage(this.resources.getString(R.string.external_repository_dialog_text))
.setPositiveButton(R.string.dialog_ok) { _, _ ->
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
- startActivityForResult(Intent.createChooser(i, "Choose Directory"), SELECT_GIT_DIRECTORY)
+ registerForActivityResult(StartActivityForResult()) { result ->
+ if (!validateResult(result)) return@registerForActivityResult
+ val uri = result.data?.data
+
+ tag(TAG).d { "Selected repository URI is $uri" }
+ // TODO: This is fragile. Workaround until PasswordItem is backed by DocumentFile
+ val docId = DocumentsContract.getTreeDocumentId(uri)
+ val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+ val path = if (split.size > 1) split[1] else split[0]
+ val repoPath = "${Environment.getExternalStorageDirectory()}/$path"
+ val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
+
+ tag(TAG).d { "Selected repository path is $repoPath" }
+
+ if (Environment.getExternalStorageDirectory().path == repoPath) {
+ MaterialAlertDialogBuilder(this)
+ .setTitle(getString(R.string.sdcard_root_warning_title))
+ .setMessage(getString(R.string.sdcard_root_warning_message))
+ .setPositiveButton("Remove everything") { _, _ ->
+ prefs.edit { putString(PreferenceKeys.GIT_EXTERNAL_REPO, uri?.path) }
+ }
+ .setNegativeButton(R.string.dialog_cancel, null)
+ .show()
+ }
+ prefs.edit { putString(PreferenceKeys.GIT_EXTERNAL_REPO, repoPath) }
+
+ }.launch(Intent.createChooser(i, "Choose Directory"))
}
.setNegativeButton(R.string.dialog_cancel, null)
.show()
@@ -529,7 +556,7 @@ class UserPreference : AppCompatActivity() {
// as you specify a parent activity in AndroidManifest.xml.
return when (item.itemId) {
android.R.id.home -> {
- setResult(Activity.RESULT_OK)
+ setResult(RESULT_OK)
finish()
true
}
@@ -538,22 +565,74 @@ class UserPreference : AppCompatActivity() {
}
/**
+ * Given a [ActivityResult], validates that the result is usable.
+ */
+ private fun validateResult(result: ActivityResult): Boolean {
+ if (result.resultCode != RESULT_OK) {
+ return false
+ }
+ if (result.data == null) {
+ setResult(RESULT_CANCELED)
+ return false
+ }
+ return true
+ }
+
+ /**
* Opens a file explorer to import the private key
*/
private fun getSshKey() {
- val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
+ registerForActivityResult(StartActivityForResult()) { result ->
+ if (!validateResult(result)) return@registerForActivityResult
+ try {
+ val uri: Uri = result.data?.data ?: throw IOException("Unable to open file")
+
+ copySshKey(uri)
+
+ Toast.makeText(
+ this,
+ this.resources.getString(R.string.ssh_key_success_dialog_title),
+ Toast.LENGTH_LONG
+ ).show()
+ val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
+
+ prefs.edit { putBoolean(PreferenceKeys.USE_GENERATED_KEY, false) }
+ getEncryptedPrefs("git_operation").edit { remove(PreferenceKeys.SSH_KEY_LOCAL_PASSPHRASE) }
+
+ // Delete the public key from generation
+ File("""$filesDir/.ssh_key.pub""").delete()
+ setResult(RESULT_OK)
+
+ finish()
+ } catch (e: Exception) {
+ MaterialAlertDialogBuilder(this)
+ .setTitle(resources.getString(R.string.ssh_key_error_dialog_title))
+ .setMessage(e.message)
+ .setPositiveButton(resources.getString(R.string.dialog_ok), null)
+ .show()
+ }
+ }.launch(Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "*/*"
- }
- startActivityForResult(intent, IMPORT_SSH_KEY)
+ })
}
/**
* Exports the passwords
*/
private fun exportPasswords() {
- val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
- startActivityForResult(Intent.createChooser(i, "Choose Directory"), EXPORT_PASSWORDS)
+ registerForActivityResult(StartActivityForResult()) { result ->
+ if (!validateResult(result)) return@registerForActivityResult
+ val uri = result.data?.data
+
+ if (uri != null) {
+ val targetDirectory = DocumentFile.fromTreeUri(applicationContext, uri)
+
+ if (targetDirectory != null) {
+ exportPasswords(targetDirectory)
+ }
+ }
+ }.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE))
}
/**
@@ -563,7 +642,7 @@ class UserPreference : AppCompatActivity() {
val intent = Intent(applicationContext, SshKeyGenActivity::class.java)
startActivity(intent)
if (!fromPreferences) {
- setResult(Activity.RESULT_OK)
+ setResult(RESULT_OK)
finish()
}
}
@@ -572,11 +651,33 @@ class UserPreference : AppCompatActivity() {
* Pick custom xkpwd dictionary from sdcard
*/
private fun storeCustomDictionaryPath() {
- val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
+ registerForActivityResult(StartActivityForResult()) { result ->
+ if (!validateResult(result)) return@registerForActivityResult
+ val uri: Uri = result.data?.data ?: throw IOException("Unable to open file")
+
+ Toast.makeText(
+ this,
+ this.resources.getString(R.string.xkpwgen_custom_dict_imported, uri.path),
+ Toast.LENGTH_SHORT
+ ).show()
+ val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
+
+ prefs.edit { putString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, uri.toString()) }
+
+ val customDictPref = prefsFragment.findPreference<Preference>(PreferenceKeys.PREF_KEY_CUSTOM_DICT)
+ setCustomDictSummary(customDictPref, uri)
+ // copy user selected file to internal storage
+ val inputStream = contentResolver.openInputStream(uri)
+ val customDictFile = File(filesDir.toString(), XkpwdDictionary.XKPWD_CUSTOM_DICT_FILE).outputStream()
+ inputStream?.copyTo(customDictFile, 1024)
+ inputStream?.close()
+ customDictFile.close()
+
+ setResult(RESULT_OK)
+ }.launch(Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "*/*"
- }
- startActivityForResult(intent, SET_CUSTOM_XKPWD_DICT)
+ })
}
@Throws(IllegalArgumentException::class, IOException::class)
@@ -631,111 +732,6 @@ class UserPreference : AppCompatActivity() {
return autofillManager?.hasEnabledAutofillServices() == true
}
- override fun onActivityResult(
- requestCode: Int,
- resultCode: Int,
- data: Intent?
- ) {
- if (resultCode == Activity.RESULT_OK) {
- if (data == null) {
- setResult(Activity.RESULT_CANCELED)
- return
- }
-
- when (requestCode) {
- IMPORT_SSH_KEY -> {
- try {
- val uri: Uri = data.data ?: throw IOException("Unable to open file")
-
- copySshKey(uri)
-
- Toast.makeText(
- this,
- this.resources.getString(R.string.ssh_key_success_dialog_title),
- Toast.LENGTH_LONG
- ).show()
- val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
-
- prefs.edit { putBoolean(PreferenceKeys.USE_GENERATED_KEY, false) }
- getEncryptedPrefs("git_operation").edit { remove(PreferenceKeys.SSH_KEY_LOCAL_PASSPHRASE) }
-
- // Delete the public key from generation
- File("""$filesDir/.ssh_key.pub""").delete()
- setResult(Activity.RESULT_OK)
-
- finish()
- } catch (e: Exception) {
- MaterialAlertDialogBuilder(this)
- .setTitle(resources.getString(R.string.ssh_key_error_dialog_title))
- .setMessage(e.message)
- .setPositiveButton(resources.getString(R.string.dialog_ok), null)
- .show()
- }
- }
- SELECT_GIT_DIRECTORY -> {
- val uri = data.data
-
- tag(TAG).d { "Selected repository URI is $uri" }
- // TODO: This is fragile. Workaround until PasswordItem is backed by DocumentFile
- val docId = DocumentsContract.getTreeDocumentId(uri)
- val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
- val path = if (split.size > 1) split[1] else split[0]
- val repoPath = "${Environment.getExternalStorageDirectory()}/$path"
- val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
-
- tag(TAG).d { "Selected repository path is $repoPath" }
-
- if (Environment.getExternalStorageDirectory().path == repoPath) {
- MaterialAlertDialogBuilder(this)
- .setTitle(getString(R.string.sdcard_root_warning_title))
- .setMessage(getString(R.string.sdcard_root_warning_message))
- .setPositiveButton("Remove everything") { _, _ ->
- prefs.edit { putString(PreferenceKeys.GIT_EXTERNAL_REPO, uri?.path) }
- }
- .setNegativeButton(R.string.dialog_cancel, null)
- .show()
- }
- prefs.edit { putString(PreferenceKeys.GIT_EXTERNAL_REPO, repoPath) }
- }
- EXPORT_PASSWORDS -> {
- val uri = data.data
-
- if (uri != null) {
- val targetDirectory = DocumentFile.fromTreeUri(applicationContext, uri)
-
- if (targetDirectory != null) {
- exportPasswords(targetDirectory)
- }
- }
- }
- SET_CUSTOM_XKPWD_DICT -> {
- val uri: Uri = data.data ?: throw IOException("Unable to open file")
-
- Toast.makeText(
- this,
- this.resources.getString(R.string.xkpwgen_custom_dict_imported, uri.path),
- Toast.LENGTH_SHORT
- ).show()
- val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
-
- prefs.edit { putString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, uri.toString()) }
-
- val customDictPref = prefsFragment.findPreference<Preference>(PreferenceKeys.PREF_KEY_CUSTOM_DICT)
- setCustomDictSummary(customDictPref, uri)
- // copy user selected file to internal storage
- val inputStream = contentResolver.openInputStream(uri)
- val customDictFile = File(filesDir.toString(), XkpwdDictionary.XKPWD_CUSTOM_DICT_FILE).outputStream()
- inputStream?.copyTo(customDictFile, 1024)
- inputStream?.close()
- customDictFile.close()
-
- setResult(Activity.RESULT_OK)
- }
- }
- }
- super.onActivityResult(requestCode, resultCode, data)
- }
-
/**
* Exports passwords to the given directory.
*
@@ -808,11 +804,6 @@ class UserPreference : AppCompatActivity() {
}
companion object {
- private const val IMPORT_SSH_KEY = 1
- private const val SELECT_GIT_DIRECTORY = 2
- private const val EXPORT_PASSWORDS = 3
- private const val EDIT_GIT_CONFIG = 4
- private const val SET_CUSTOM_XKPWD_DICT = 5
private const val TAG = "UserPreference"
/**