diff options
| author | Harsh Shandilya <msfjarvis@gmail.com> | 2020-07-03 12:54:06 +0530 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-07-03 09:24:06 +0200 |
| commit | 25b426157417c97c61c3d2cc0d9fa556f337f22d (patch) | |
| tree | f53331d7ee2d5b780ebf20a6ccdded53bda42005 /app/src/main/java/com/zeapo/pwdstore/UserPreference.kt | |
| parent | ff3d2fcce3f1d74bdb1e13e3634f1ea9a9f9f1e5 (diff) | |
| download | HardenedPass-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.kt | 241 |
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" /** |
