From 3dace243e4b0fe1378e2d81c46fb70cb236e6ae5 Mon Sep 17 00:00:00 2001 From: Fabian Henneke Date: Thu, 6 Aug 2020 10:58:20 +0200 Subject: Refactor uses of applicationContext and startActivityForResult (#997) * Refactor uses of applicationContext and startActivityForResult This commit applies three types of refactoring: 1. Remove context argument from PasswordRepository companion functions by relying on Application.instance. 2. Introduce a sharedPrefs extension function on Context that returns the default SharedPreferences for the applicationContext. 3. Use OpenDocument() and OpenDocumentTree() contracts. * Drop toPasswordItem argument --- .../main/java/com/zeapo/pwdstore/Application.kt | 14 +- .../java/com/zeapo/pwdstore/ClipboardService.kt | 3 +- .../main/java/com/zeapo/pwdstore/LaunchActivity.kt | 3 +- .../com/zeapo/pwdstore/PasswordExportService.kt | 2 +- .../java/com/zeapo/pwdstore/PasswordFragment.kt | 14 +- .../main/java/com/zeapo/pwdstore/PasswordStore.kt | 39 +++--- .../pwdstore/SearchableRepositoryViewModel.kt | 23 ++-- .../com/zeapo/pwdstore/SelectFolderActivity.kt | 2 +- .../main/java/com/zeapo/pwdstore/UserPreference.kt | 150 +++++++++------------ .../com/zeapo/pwdstore/autofill/AutofillService.kt | 16 +-- .../zeapo/pwdstore/autofill/oreo/AutofillHelper.kt | 2 +- .../pwdstore/autofill/oreo/AutofillPreferences.kt | 7 +- .../autofill/oreo/PublicSuffixListCache.kt | 4 +- .../autofill/oreo/ui/AutofillSaveActivity.kt | 2 +- .../com/zeapo/pwdstore/crypto/BasePgpActivity.kt | 3 +- .../pwdstore/crypto/PasswordCreationActivity.kt | 4 +- .../java/com/zeapo/pwdstore/git/BaseGitActivity.kt | 6 +- .../com/zeapo/pwdstore/git/GitConfigActivity.kt | 2 +- .../zeapo/pwdstore/git/GitServerConfigActivity.kt | 4 +- .../zeapo/pwdstore/git/operation/GitOperation.kt | 4 +- .../zeapo/pwdstore/pwgenxkpwd/XkpwdDictionary.kt | 3 +- .../zeapo/pwdstore/sshkeygen/SshKeyGenActivity.kt | 4 +- .../ui/adapters/PasswordItemRecyclerAdapter.kt | 4 +- .../java/com/zeapo/pwdstore/utils/Extensions.kt | 10 +- .../com/zeapo/pwdstore/utils/PasswordRepository.kt | 23 ++-- 25 files changed, 158 insertions(+), 190 deletions(-) diff --git a/app/src/main/java/com/zeapo/pwdstore/Application.kt b/app/src/main/java/com/zeapo/pwdstore/Application.kt index 611ccfe0..c3b9a90d 100644 --- a/app/src/main/java/com/zeapo/pwdstore/Application.kt +++ b/app/src/main/java/com/zeapo/pwdstore/Application.kt @@ -15,27 +15,25 @@ import com.github.ajalt.timberkt.Timber.DebugTree import com.github.ajalt.timberkt.Timber.plant import com.zeapo.pwdstore.git.config.setUpBouncyCastleForSshj import com.zeapo.pwdstore.utils.PreferenceKeys +import com.zeapo.pwdstore.utils.sharedPrefs @Suppress("Unused") class Application : android.app.Application(), SharedPreferences.OnSharedPreferenceChangeListener { - private var prefs: SharedPreferences? = null - override fun onCreate() { super.onCreate() instance = this - prefs = PreferenceManager.getDefaultSharedPreferences(this) - if (BuildConfig.ENABLE_DEBUG_FEATURES || prefs?.getBoolean(PreferenceKeys.ENABLE_DEBUG_LOGGING, false) == - true) { + if (BuildConfig.ENABLE_DEBUG_FEATURES || + sharedPrefs.getBoolean(PreferenceKeys.ENABLE_DEBUG_LOGGING, false)) { plant(DebugTree()) } - prefs?.registerOnSharedPreferenceChangeListener(this) + sharedPrefs.registerOnSharedPreferenceChangeListener(this) setNightMode() setUpBouncyCastleForSshj() } override fun onTerminate() { - prefs?.unregisterOnSharedPreferenceChangeListener(this) + sharedPrefs.unregisterOnSharedPreferenceChangeListener(this) super.onTerminate() } @@ -46,7 +44,7 @@ class Application : android.app.Application(), SharedPreferences.OnSharedPrefere } private fun setNightMode() { - AppCompatDelegate.setDefaultNightMode(when (prefs?.getString(PreferenceKeys.APP_THEME, getString(R.string.app_theme_def))) { + AppCompatDelegate.setDefaultNightMode(when (sharedPrefs.getString(PreferenceKeys.APP_THEME, getString(R.string.app_theme_def))) { "light" -> MODE_NIGHT_NO "dark" -> MODE_NIGHT_YES "follow_system" -> MODE_NIGHT_FOLLOW_SYSTEM diff --git a/app/src/main/java/com/zeapo/pwdstore/ClipboardService.kt b/app/src/main/java/com/zeapo/pwdstore/ClipboardService.kt index 363e35ab..20a36539 100644 --- a/app/src/main/java/com/zeapo/pwdstore/ClipboardService.kt +++ b/app/src/main/java/com/zeapo/pwdstore/ClipboardService.kt @@ -19,6 +19,7 @@ import androidx.preference.PreferenceManager import com.github.ajalt.timberkt.d import com.zeapo.pwdstore.utils.PreferenceKeys import com.zeapo.pwdstore.utils.clipboard +import com.zeapo.pwdstore.utils.sharedPrefs import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -31,7 +32,7 @@ import kotlinx.coroutines.withContext class ClipboardService : Service() { private val scope = CoroutineScope(Job() + Dispatchers.Main) - private val settings: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(this) } + private val settings: SharedPreferences by lazy { sharedPrefs } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { if (intent != null) { diff --git a/app/src/main/java/com/zeapo/pwdstore/LaunchActivity.kt b/app/src/main/java/com/zeapo/pwdstore/LaunchActivity.kt index d4622d86..71f59851 100644 --- a/app/src/main/java/com/zeapo/pwdstore/LaunchActivity.kt +++ b/app/src/main/java/com/zeapo/pwdstore/LaunchActivity.kt @@ -13,12 +13,13 @@ import androidx.preference.PreferenceManager import com.zeapo.pwdstore.crypto.DecryptActivity import com.zeapo.pwdstore.utils.BiometricAuthenticator import com.zeapo.pwdstore.utils.PreferenceKeys +import com.zeapo.pwdstore.utils.sharedPrefs class LaunchActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - val prefs = PreferenceManager.getDefaultSharedPreferences(this) + val prefs = sharedPrefs if (prefs.getBoolean(PreferenceKeys.BIOMETRIC_AUTH, false)) { BiometricAuthenticator.authenticate(this) { when (it) { diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordExportService.kt b/app/src/main/java/com/zeapo/pwdstore/PasswordExportService.kt index c1845f2f..fc2b7f10 100644 --- a/app/src/main/java/com/zeapo/pwdstore/PasswordExportService.kt +++ b/app/src/main/java/com/zeapo/pwdstore/PasswordExportService.kt @@ -58,7 +58,7 @@ class PasswordExportService : Service() { */ private fun exportPasswords(targetDirectory: DocumentFile) { - val repositoryDirectory = requireNotNull(PasswordRepository.getRepositoryDirectory(applicationContext)) + val repositoryDirectory = requireNotNull(PasswordRepository.getRepositoryDirectory()) val sourcePassDir = DocumentFile.fromFile(repositoryDirectory) d { "Copying ${repositoryDirectory.path} to $targetDirectory" } diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt b/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt index 355d4578..c9d00353 100644 --- a/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt +++ b/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt @@ -18,7 +18,6 @@ import androidx.activity.result.contract.ActivityResultContracts.StartActivityFo import androidx.appcompat.view.ActionMode import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.snackbar.Snackbar @@ -33,6 +32,7 @@ import com.zeapo.pwdstore.ui.dialogs.ItemCreationBottomSheet import com.zeapo.pwdstore.utils.PasswordItem import com.zeapo.pwdstore.utils.PasswordRepository import com.zeapo.pwdstore.utils.PreferenceKeys +import com.zeapo.pwdstore.utils.sharedPrefs import com.zeapo.pwdstore.utils.viewBinding import java.io.File import me.zhanghai.android.fastscroll.FastScrollerBuilder @@ -59,7 +59,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - settings = PreferenceManager.getDefaultSharedPreferences(requireContext()) + settings = requireContext().sharedPrefs initializePasswordList() binding.fab.setOnClickListener { ItemCreationBottomSheet().show(childFragmentManager, "BOTTOM_SHEET") @@ -73,7 +73,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) { } private fun initializePasswordList() { - val gitDir = File(PasswordRepository.getRepositoryDirectory(requireContext()), ".git") + val gitDir = File(PasswordRepository.getRepositoryDirectory(), ".git") val hasGitDir = gitDir.exists() && gitDir.isDirectory && (gitDir.listFiles()?.isNotEmpty() == true) binding.swipeRefresher.setOnRefreshListener { if (!hasGitDir) { @@ -180,7 +180,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) { // may be called multiple times if the mode is invalidated. override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean { menu.findItem(R.id.menu_edit_password).isVisible = - recyclerAdapter.getSelectedItems(requireContext()) + recyclerAdapter.getSelectedItems() .all { it.type == PasswordItem.TYPE_CATEGORY } return true } @@ -189,17 +189,17 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) { override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { return when (item.itemId) { R.id.menu_delete_password -> { - requireStore().deletePasswords(recyclerAdapter.getSelectedItems(requireContext())) + requireStore().deletePasswords(recyclerAdapter.getSelectedItems()) // Action picked, so close the CAB mode.finish() true } R.id.menu_move_password -> { - requireStore().movePasswords(recyclerAdapter.getSelectedItems(requireContext())) + requireStore().movePasswords(recyclerAdapter.getSelectedItems()) false } R.id.menu_edit_password -> { - requireStore().renameCategory(recyclerAdapter.getSelectedItems(requireContext())) + requireStore().renameCategory(recyclerAdapter.getSelectedItems()) mode.finish() false } diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.kt b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.kt index a4ada3c5..3f31a2c5 100644 --- a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.kt +++ b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.kt @@ -69,6 +69,7 @@ import com.zeapo.pwdstore.utils.contains import com.zeapo.pwdstore.utils.isInsideRepository import com.zeapo.pwdstore.utils.listFilesRecursively import com.zeapo.pwdstore.utils.requestInputFocusOnView +import com.zeapo.pwdstore.utils.sharedPrefs import java.io.File import java.lang.Character.UnicodeBlock import kotlinx.coroutines.Dispatchers @@ -83,10 +84,11 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { private lateinit var activity: PasswordStore private lateinit var searchItem: MenuItem private lateinit var searchView: SearchView - private lateinit var settings: SharedPreferences private var plist: PasswordFragment? = null private var shortcutManager: ShortcutManager? = null + private val settings by lazy { sharedPrefs } + private val model: SearchableRepositoryViewModel by viewModels { ViewModelProvider.AndroidViewModelFactory(application) } @@ -119,7 +121,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { dir.exists() && dir.isDirectory && dir.listFilesRecursively().isNotEmpty() && - getPasswords(dir, getRepositoryDirectory(this), sortOrder).isNotEmpty()) { + getPasswords(dir, getRepositoryDirectory(), sortOrder).isNotEmpty()) { closeRepository() checkLocalRepository() return@registerForActivityResult @@ -153,7 +155,6 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { @SuppressLint("NewApi") override fun onCreate(savedInstanceState: Bundle?) { activity = this - settings = PreferenceManager.getDefaultSharedPreferences(this.applicationContext) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { shortcutManager = getSystemService() } @@ -209,7 +210,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { } model.currentDir.observe(this) { dir -> - val basePath = getRepositoryDirectory(applicationContext).absoluteFile + val basePath = getRepositoryDirectory().absoluteFile supportActionBar!!.apply { if (dir != basePath) title = dir.name @@ -379,9 +380,9 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { private fun createRepository() { if (!isInitialized) { - initialize(this) + initialize() } - val localDir = getRepositoryDirectory(applicationContext) + val localDir = getRepositoryDirectory() try { check(localDir.mkdir()) { "Failed to create directory!" } createRepository(localDir) @@ -409,7 +410,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { if (externalRepo && externalRepoPath != null) { val dir = File(externalRepoPath) if (dir.exists() && dir.isDirectory && - getPasswords(dir, getRepositoryDirectory(this), sortOrder).isNotEmpty()) { + getPasswords(dir, getRepositoryDirectory(), sortOrder).isNotEmpty()) { closeRepository() checkLocalRepository() return // if not empty, just show me the passwords! @@ -449,7 +450,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { } private fun checkLocalRepository() { - val repo = initialize(this) + val repo = initialize() if (repo == null) { val intent = Intent(activity, UserPreference::class.java) intent.putExtra("operation", "git_external") @@ -459,7 +460,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { } }.launch(intent) } else { - checkLocalRepository(getRepositoryDirectory(applicationContext)) + checkLocalRepository(getRepositoryDirectory()) } } @@ -472,7 +473,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { settings.edit { putBoolean(PreferenceKeys.REPO_CHANGED, false) } plist = PasswordFragment() val args = Bundle() - args.putString(REQUEST_ARG_PATH, getRepositoryDirectory(applicationContext).absolutePath) + args.putString(REQUEST_ARG_PATH, getRepositoryDirectory().absolutePath) // if the activity was started from the autofill settings, the // intent is to match a clicked pwd with app. pass this to fragment @@ -506,7 +507,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { } private fun getLastChangedTimestamp(fullPath: String): Long { - val repoPath = getRepositoryDirectory(this) + val repoPath = getRepositoryDirectory() val repository = getRepository(repoPath) if (repository == null) { d { "getLastChangedTimestamp: No git repository" } @@ -534,7 +535,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { for (intent in arrayOf(decryptIntent, authDecryptIntent)) { intent.putExtra("NAME", item.toString()) intent.putExtra("FILE_PATH", item.file.absolutePath) - intent.putExtra("REPO_PATH", getRepositoryDirectory(applicationContext).absolutePath) + intent.putExtra("REPO_PATH", getRepositoryDirectory().absolutePath) intent.putExtra("LAST_CHANGED_TIMESTAMP", getLastChangedTimestamp(item.file.absolutePath)) } // Needs an action to be a shortcut intent @@ -577,7 +578,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { i { "Adding file to : ${currentDir.absolutePath}" } val intent = Intent(this, PasswordCreationActivity::class.java) intent.putExtra("FILE_PATH", currentDir.absolutePath) - intent.putExtra("REPO_PATH", getRepositoryDirectory(applicationContext).absolutePath) + intent.putExtra("REPO_PATH", getRepositoryDirectory().absolutePath) registerForActivityResult(StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { lifecycleScope.launch { @@ -623,7 +624,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { refreshPasswordList() AutofillMatcher.updateMatches(applicationContext, delete = filesToDelete) val fmt = selectedItems.joinToString(separator = ", ") { item -> - item.file.toRelativeString(getRepositoryDirectory(this@PasswordStore)) + item.file.toRelativeString(getRepositoryDirectory()) } lifecycleScope.launch { commitChange( @@ -645,7 +646,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { val intentData = result.data ?: return@registerForActivityResult val filesToMove = requireNotNull(intentData.getStringArrayExtra("Files")) val target = File(requireNotNull(intentData.getStringExtra("SELECTED_FOLDER_PATH"))) - val repositoryPath = getRepositoryDirectory(applicationContext).absolutePath + val repositoryPath = getRepositoryDirectory().absolutePath if (!target.isDirectory) { e { "Tried moving passwords to a non-existing folder." } return@registerForActivityResult @@ -703,7 +704,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { } } else -> { - val repoDir = getRepositoryDirectory(applicationContext).absolutePath + val repoDir = getRepositoryDirectory().absolutePath val relativePath = getRelativePath("${target.absolutePath}/", repoDir) withContext(Dispatchers.Main) { commitChange( @@ -756,7 +757,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { when { newCategoryEditText.text.isNullOrBlank() -> renameCategory(oldCategory, CategoryRenameError.EmptyField) newCategory.exists() -> renameCategory(oldCategory, CategoryRenameError.CategoryExists) - !isInsideRepository(newCategory) -> renameCategory(oldCategory, CategoryRenameError.DestinationOutsideRepo) + !newCategory.isInsideRepository() -> renameCategory(oldCategory, CategoryRenameError.DestinationOutsideRepo) else -> lifecycleScope.launch(Dispatchers.IO) { moveFile(oldCategory.file, newCategory) withContext(Dispatchers.Main) { @@ -803,7 +804,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { } private val currentDir: File - get() = plist?.currentDir ?: getRepositoryDirectory(applicationContext) + get() = plist?.currentDir ?: getRepositoryDirectory() private suspend fun moveFile(source: File, destinationFile: File) { val sourceDestinationMap = if (source.isDirectory) { @@ -887,7 +888,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) { fun matchPasswordWithApp(item: PasswordItem) { val path = item.file .absolutePath - .replace(getRepositoryDirectory(applicationContext).toString() + "/", "") + .replace(getRepositoryDirectory().toString() + "/", "") .replace(".gpg", "") val data = Intent() data.putExtra("path", path) diff --git a/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt b/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt index 4d713afa..f1728d6d 100644 --- a/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt +++ b/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt @@ -5,7 +5,6 @@ package com.zeapo.pwdstore import android.app.Application -import android.content.Context import android.os.Parcelable import android.view.LayoutInflater import android.view.View @@ -31,6 +30,7 @@ import com.zeapo.pwdstore.autofill.oreo.DirectoryStructure import com.zeapo.pwdstore.utils.PasswordItem import com.zeapo.pwdstore.utils.PasswordRepository import com.zeapo.pwdstore.utils.PreferenceKeys +import com.zeapo.pwdstore.utils.sharedPrefs import java.io.File import java.text.Collator import java.util.Locale @@ -50,10 +50,10 @@ import kotlinx.coroutines.flow.toList import kotlinx.coroutines.yield import me.zhanghai.android.fastscroll.PopupTextProvider -private fun File.toPasswordItem(root: File) = if (isFile) - PasswordItem.newPassword(name, this, root) +private fun File.toPasswordItem() = if (isFile) + PasswordItem.newPassword(name, this, PasswordRepository.getRepositoryDirectory()) else - PasswordItem.newCategory(name, this, root) + PasswordItem.newCategory(name, this, PasswordRepository.getRepositoryDirectory()) private fun PasswordItem.fuzzyMatch(filter: String): Int { var i = 0 @@ -138,8 +138,8 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel } private val root - get() = PasswordRepository.getRepositoryDirectory(getApplication()) - private val settings = PreferenceManager.getDefaultSharedPreferences(getApplication()) + get() = PasswordRepository.getRepositoryDirectory() + private val settings by lazy { application.sharedPrefs } private val showHiddenDirs get() = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false) private val defaultSearchMode @@ -216,7 +216,7 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel val passwordList = when (filterModeToUse) { FilterMode.NoFilter -> { prefilteredResultFlow - .map { it.toPasswordItem(root) } + .map { it.toPasswordItem() } .toList() .sortedWith(itemComparator) } @@ -228,7 +228,7 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel .filter { absoluteFile -> regex.containsMatchIn(absoluteFile.relativeTo(root).path) } - .map { it.toPasswordItem(root) } + .map { it.toPasswordItem() } .toList() .sortedWith(itemComparator) } else { @@ -238,7 +238,7 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel FilterMode.Fuzzy -> { prefilteredResultFlow .map { - val item = it.toPasswordItem(root) + val item = it.toPasswordItem() Pair(item.fuzzyMatch(searchAction.filter), item) } .filter { it.first > 0 } @@ -443,10 +443,7 @@ open class SearchableRepositoryAdapter( private val selectedFiles get() = requireSelectionTracker().selection.map { File(it) } - fun getSelectedItems(context: Context): List { - val root = PasswordRepository.getRepositoryDirectory(context) - return selectedFiles.map { it.toPasswordItem(root) } - } + fun getSelectedItems() = selectedFiles.map { it.toPasswordItem() } fun getPositionForFile(file: File) = itemKeyProvider.getPosition(file.absolutePath) diff --git a/app/src/main/java/com/zeapo/pwdstore/SelectFolderActivity.kt b/app/src/main/java/com/zeapo/pwdstore/SelectFolderActivity.kt index 10ed77db..752b46f3 100644 --- a/app/src/main/java/com/zeapo/pwdstore/SelectFolderActivity.kt +++ b/app/src/main/java/com/zeapo/pwdstore/SelectFolderActivity.kt @@ -22,7 +22,7 @@ class SelectFolderActivity : AppCompatActivity(R.layout.select_folder_layout) { passwordList = SelectFolderFragment() val args = Bundle() - args.putString(PasswordStore.REQUEST_ARG_PATH, PasswordRepository.getRepositoryDirectory(applicationContext).absolutePath) + args.putString(PasswordStore.REQUEST_ARG_PATH, PasswordRepository.getRepositoryDirectory().absolutePath) passwordList.arguments = args diff --git a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt index 8938df00..43cab0a0 100644 --- a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt +++ b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt @@ -6,6 +6,7 @@ package com.zeapo.pwdstore import android.accessibilityservice.AccessibilityServiceInfo import android.annotation.SuppressLint +import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.content.pm.ShortcutManager @@ -20,8 +21,8 @@ import android.text.TextUtils import android.view.MenuItem import android.view.accessibility.AccessibilityManager import android.widget.Toast -import androidx.activity.result.ActivityResult -import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult +import androidx.activity.result.contract.ActivityResultContracts.OpenDocument +import androidx.activity.result.contract.ActivityResultContracts.OpenDocumentTree import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.AppCompatTextView import androidx.biometric.BiometricManager @@ -53,6 +54,7 @@ import com.zeapo.pwdstore.utils.PasswordRepository import com.zeapo.pwdstore.utils.PreferenceKeys import com.zeapo.pwdstore.utils.autofillManager import com.zeapo.pwdstore.utils.getEncryptedPrefs +import com.zeapo.pwdstore.utils.sharedPrefs import java.io.File import java.io.IOException @@ -69,15 +71,15 @@ class UserPreference : AppCompatActivity() { private var clearSavedPassPreference: Preference? = null private lateinit var autofillDependencies: List private lateinit var oreoAutofillDependencies: List - private lateinit var callingActivity: UserPreference + private lateinit var prefsActivity: UserPreference private lateinit var sharedPreferences: SharedPreferences private lateinit var encryptedPreferences: SharedPreferences override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - callingActivity = requireActivity() as UserPreference + prefsActivity = requireActivity() as UserPreference val context = requireContext() sharedPreferences = preferenceManager.sharedPreferences - encryptedPreferences = requireActivity().applicationContext.getEncryptedPrefs("git_operation") + encryptedPreferences = requireActivity().getEncryptedPrefs("git_operation") addPreferencesFromResource(R.xml.preference) @@ -152,12 +154,12 @@ class UserPreference : AppCompatActivity() { appVersionPreference?.summary = "Version: ${BuildConfig.VERSION_NAME}" sshKeyPreference?.onPreferenceClickListener = ClickListener { - callingActivity.getSshKey() + prefsActivity.getSshKey() true } sshKeygenPreference?.onPreferenceClickListener = ClickListener { - callingActivity.makeSshKey(true) + prefsActivity.makeSshKey(true) true } @@ -185,24 +187,24 @@ class UserPreference : AppCompatActivity() { } gitServerPreference?.onPreferenceClickListener = ClickListener { - startActivity(Intent(callingActivity, GitServerConfigActivity::class.java)) + startActivity(Intent(prefsActivity, GitServerConfigActivity::class.java)) true } gitConfigPreference?.onPreferenceClickListener = ClickListener { - startActivity(Intent(callingActivity, GitConfigActivity::class.java)) + startActivity(Intent(prefsActivity, GitConfigActivity::class.java)) true } deleteRepoPreference?.onPreferenceClickListener = ClickListener { - val repoDir = PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext) - MaterialAlertDialogBuilder(callingActivity) + val repoDir = PasswordRepository.getRepositoryDirectory() + MaterialAlertDialogBuilder(prefsActivity) .setTitle(R.string.pref_dialog_delete_title) .setMessage(resources.getString(R.string.dialog_delete_msg, repoDir)) .setCancelable(false) .setPositiveButton(R.string.dialog_delete) { dialogInterface, _ -> try { - PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext).deleteRecursively() + PasswordRepository.getRepositoryDirectory().deleteRecursively() PasswordRepository.closeRepository() } catch (ignored: Exception) { // TODO Handle the different cases of exceptions @@ -215,7 +217,7 @@ class UserPreference : AppCompatActivity() { } sharedPreferences.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false) } dialogInterface.cancel() - callingActivity.finish() + prefsActivity.finish() } .setNegativeButton(R.string.dialog_do_not_delete) { dialogInterface, _ -> run { dialogInterface.cancel() } } .show() @@ -226,7 +228,7 @@ class UserPreference : AppCompatActivity() { selectExternalGitRepositoryPreference?.summary = sharedPreferences.getString(PreferenceKeys.GIT_EXTERNAL_REPO, context.getString(R.string.no_repo_selected)) selectExternalGitRepositoryPreference?.onPreferenceClickListener = ClickListener { - callingActivity.selectExternalGitRepository() + prefsActivity.selectExternalGitRepository() true } @@ -241,7 +243,7 @@ class UserPreference : AppCompatActivity() { externalGitRepositoryPreference?.onPreferenceChangeListener = resetRepo autoFillAppsPreference?.onPreferenceClickListener = ClickListener { - val intent = Intent(callingActivity, AutofillPreferenceActivity::class.java) + val intent = Intent(prefsActivity, AutofillPreferenceActivity::class.java) startActivity(intent) true } @@ -254,7 +256,7 @@ class UserPreference : AppCompatActivity() { findPreference(PreferenceKeys.EXPORT_PASSWORDS)?.apply { isVisible = sharedPreferences.getBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false) onPreferenceClickListener = Preference.OnPreferenceClickListener { - callingActivity.exportPasswords() + prefsActivity.exportPasswords() true } } @@ -316,7 +318,7 @@ class UserPreference : AppCompatActivity() { val prefCustomXkpwdDictionary = findPreference(PreferenceKeys.PREF_KEY_CUSTOM_DICT) prefCustomXkpwdDictionary?.onPreferenceClickListener = ClickListener { - callingActivity.storeCustomDictionaryPath() + prefsActivity.storeCustomDictionaryPath() true } val dictUri = sharedPreferences.getString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, "") @@ -361,8 +363,8 @@ class UserPreference : AppCompatActivity() { } private fun updateAutofillSettings() { - val isAccessibilityServiceEnabled = callingActivity.isAccessibilityServiceEnabled - val isAutofillServiceEnabled = callingActivity.isAutofillServiceEnabled + val isAccessibilityServiceEnabled = prefsActivity.isAccessibilityServiceEnabled + val isAutofillServiceEnabled = prefsActivity.isAutofillServiceEnabled autoFillEnablePreference?.isChecked = isAccessibilityServiceEnabled || isAutofillServiceEnabled autofillDependencies.forEach { @@ -391,16 +393,16 @@ class UserPreference : AppCompatActivity() { } private fun onEnableAutofillClick() { - if (callingActivity.isAccessibilityServiceEnabled) { + if (prefsActivity.isAccessibilityServiceEnabled) { startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)) - } else if (callingActivity.isAutofillServiceEnabled) { + } else if (prefsActivity.isAutofillServiceEnabled) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) - callingActivity.autofillManager!!.disableAutofillServices() + prefsActivity.autofillManager!!.disableAutofillServices() else throw IllegalStateException("isAutofillServiceEnabled == true, but Build.VERSION.SDK_INT < Build.VERSION_CODES.O") } else { - val enableOreoAutofill = callingActivity.isAutofillServiceSupported - MaterialAlertDialogBuilder(callingActivity).run { + val enableOreoAutofill = prefsActivity.isAutofillServiceSupported + MaterialAlertDialogBuilder(prefsActivity).run { setTitle(R.string.pref_autofill_enable_title) if (enableOreoAutofill && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { @SuppressLint("InflateParams") @@ -480,10 +482,8 @@ class UserPreference : AppCompatActivity() { .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) - registerForActivityResult(StartActivityForResult()) { result -> - if (!validateResult(result)) return@registerForActivityResult - val uri = result.data?.data + registerForActivityResult(OpenDocumentTree()) { uri: Uri? -> + if (uri == null) return@registerForActivityResult tag(TAG).d { "Selected repository URI is $uri" } // TODO: This is fragile. Workaround until PasswordItem is backed by DocumentFile @@ -491,7 +491,7 @@ class UserPreference : AppCompatActivity() { 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) + val prefs = sharedPrefs tag(TAG).d { "Selected repository path is $repoPath" } @@ -500,14 +500,14 @@ class UserPreference : AppCompatActivity() { .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) } + 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")) + }.launch(null) } .setNegativeButton(R.string.dialog_cancel, null) .show() @@ -527,29 +527,13 @@ 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() { - registerForActivityResult(StartActivityForResult()) { result -> - if (!validateResult(result)) return@registerForActivityResult + registerForActivityResult(OpenDocument()) { uri: Uri? -> + if (uri == null) return@registerForActivityResult try { - val uri: Uri = result.data?.data ?: throw IOException("Unable to open file") - copySshKey(uri) Toast.makeText( @@ -557,7 +541,7 @@ class UserPreference : AppCompatActivity() { this.resources.getString(R.string.ssh_key_success_dialog_title), Toast.LENGTH_LONG ).show() - val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext) + val prefs = sharedPrefs prefs.edit { putBoolean(PreferenceKeys.USE_GENERATED_KEY, false) } getEncryptedPrefs("git_operation").edit { remove(PreferenceKeys.SSH_KEY_LOCAL_PASSPHRASE) } @@ -574,44 +558,39 @@ class UserPreference : AppCompatActivity() { .setPositiveButton(resources.getString(R.string.dialog_ok), null) .show() } - }.launch(Intent(Intent.ACTION_OPEN_DOCUMENT).apply { - addCategory(Intent.CATEGORY_OPENABLE) - type = "*/*" - }) + }.launch(arrayOf("*/*")) } /** * Exports the passwords */ private fun exportPasswords() { - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { - flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or - Intent.FLAG_GRANT_WRITE_URI_PERMISSION or - Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or - Intent.FLAG_GRANT_PREFIX_URI_PERMISSION - } - - 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) { - val service = Intent(applicationContext, PasswordExportService::class.java).apply { - action = PasswordExportService.ACTION_EXPORT_PASSWORD - putExtra("uri", uri) - } + registerForActivityResult(object : OpenDocumentTree() { + override fun createIntent(context: Context, input: Uri?): Intent { + return super.createIntent(context, input).apply { + flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or + Intent.FLAG_GRANT_WRITE_URI_PERMISSION or + Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or + Intent.FLAG_GRANT_PREFIX_URI_PERMISSION + } + } + }) { uri: Uri? -> + if (uri == null) return@registerForActivityResult + val targetDirectory = DocumentFile.fromTreeUri(applicationContext, uri) + + if (targetDirectory != null) { + val service = Intent(applicationContext, PasswordExportService::class.java).apply { + action = PasswordExportService.ACTION_EXPORT_PASSWORD + putExtra("uri", uri) + } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - startForegroundService(service) - } else { - startService(service) - } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + startForegroundService(service) + } else { + startService(service) } } - }.launch(intent) + }.launch(null) } /** @@ -630,18 +609,16 @@ class UserPreference : AppCompatActivity() { * Pick custom xkpwd dictionary from sdcard */ private fun storeCustomDictionaryPath() { - registerForActivityResult(StartActivityForResult()) { result -> - if (!validateResult(result)) return@registerForActivityResult - val uri: Uri = result.data?.data ?: throw IOException("Unable to open file") + registerForActivityResult(OpenDocument()) { uri -> + if (uri == null) return@registerForActivityResult 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()) } + sharedPrefs.edit { putString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, uri.toString()) } val customDictPref = prefsFragment.findPreference(PreferenceKeys.PREF_KEY_CUSTOM_DICT) setCustomDictSummary(customDictPref, uri) @@ -653,10 +630,7 @@ class UserPreference : AppCompatActivity() { customDictFile.close() setResult(RESULT_OK) - }.launch(Intent(Intent.ACTION_OPEN_DOCUMENT).apply { - addCategory(Intent.CATEGORY_OPENABLE) - type = "*/*" - }) + }.launch(arrayOf("*/*")) } @Throws(IllegalArgumentException::class, IOException::class) diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.kt index 1d3086f9..4b40d8a4 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.kt +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/AutofillService.kt @@ -76,7 +76,7 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope } fun setPickedPassword(path: String) { - items.add(File("${PasswordRepository.getRepositoryDirectory(applicationContext)}/$path.gpg")) + items.add(File("${PasswordRepository.getRepositoryDirectory()}/$path.gpg")) bindDecryptAndVerify() } @@ -296,9 +296,9 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope when (preference) { "/first" -> { if (!PasswordRepository.isInitialized) { - PasswordRepository.initialize(this) + PasswordRepository.initialize() } - items = searchPasswords(PasswordRepository.getRepositoryDirectory(this), webViewTitle) + items = searchPasswords(PasswordRepository.getRepositoryDirectory(), webViewTitle) } "/never" -> items = ArrayList() else -> getPreferredPasswords(preference) @@ -318,9 +318,9 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope when (preference) { "/first" -> { if (!PasswordRepository.isInitialized) { - PasswordRepository.initialize(this) + PasswordRepository.initialize() } - items = searchPasswords(PasswordRepository.getRepositoryDirectory(this), appName) + items = searchPasswords(PasswordRepository.getRepositoryDirectory(), appName) } "/never" -> items = ArrayList() else -> getPreferredPasswords(preference) @@ -331,12 +331,12 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope // file into the items list. private fun getPreferredPasswords(preference: String) { if (!PasswordRepository.isInitialized) { - PasswordRepository.initialize(this) + PasswordRepository.initialize() } val preferredPasswords = preference.splitLines() items = ArrayList() for (password in preferredPasswords) { - val path = PasswordRepository.getRepositoryDirectory(applicationContext).toString() + "/" + password + ".gpg" + val path = PasswordRepository.getRepositoryDirectory().toString() + "/" + password + ".gpg" if (File(path).exists()) { items.add(File(path)) } @@ -417,7 +417,7 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope // populate the dialog items, always with pick + pick and match. Could // make it optional (or make height a setting for the same effect) val itemNames = arrayOfNulls(items.size + 2) - val passwordDirectory = PasswordRepository.getRepositoryDirectory(applicationContext).toString() + val passwordDirectory = PasswordRepository.getRepositoryDirectory().toString() val autofillFullPath = settings!!.getBoolean(PreferenceKeys.AUTOFILL_FULL_PATH, false) for (i in items.indices) { if (autofillFullPath) { diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillHelper.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillHelper.kt index 361f2fee..d5c7af75 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillHelper.kt +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillHelper.kt @@ -121,7 +121,7 @@ private fun makeRemoteView( fun makeFillMatchRemoteView(context: Context, file: File, formOrigin: FormOrigin): RemoteViews { val title = formOrigin.getPrettyIdentifier(context, untrusted = false) val directoryStructure = AutofillPreferences.directoryStructure(context) - val relativeFile = file.relativeTo(PasswordRepository.getRepositoryDirectory(context)) + val relativeFile = file.relativeTo(PasswordRepository.getRepositoryDirectory()) val summary = directoryStructure.getUsernameFor(relativeFile) ?: directoryStructure.getPathToIdentifierFor(relativeFile) ?: "" val iconRes = R.drawable.ic_person_black_24dp diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillPreferences.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillPreferences.kt index 38bd375e..3e10933a 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillPreferences.kt +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillPreferences.kt @@ -9,12 +9,10 @@ import android.content.SharedPreferences import android.os.Build import androidx.annotation.RequiresApi import androidx.preference.PreferenceManager +import com.zeapo.pwdstore.utils.sharedPrefs import java.io.File import java.nio.file.Paths -private val Context.defaultSharedPreferences: SharedPreferences - get() = PreferenceManager.getDefaultSharedPreferences(this) - enum class DirectoryStructure(val value: String) { EncryptedUsername("encrypted_username"), FileBased("file"), @@ -122,8 +120,7 @@ enum class DirectoryStructure(val value: String) { object AutofillPreferences { fun directoryStructure(context: Context): DirectoryStructure { - val value = - context.defaultSharedPreferences.getString(DirectoryStructure.PREFERENCE, null) + val value = context.sharedPrefs.getString(DirectoryStructure.PREFERENCE, null) return DirectoryStructure.fromValue(value) } } diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/PublicSuffixListCache.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/PublicSuffixListCache.kt index ab4f134a..536357f5 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/PublicSuffixListCache.kt +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/PublicSuffixListCache.kt @@ -8,6 +8,7 @@ import android.content.Context import android.util.Patterns import androidx.preference.PreferenceManager import com.zeapo.pwdstore.utils.PreferenceKeys +import com.zeapo.pwdstore.utils.sharedPrefs import kotlinx.coroutines.runBlocking import mozilla.components.lib.publicsuffixlist.PublicSuffixList @@ -68,8 +69,7 @@ fun getSuffixPlusUpToOne(domain: String, suffix: String): String? { } fun getCustomSuffixes(context: Context): Sequence { - val prefs = PreferenceManager.getDefaultSharedPreferences(context) - return prefs.getString(PreferenceKeys.OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES, "")!! + return context.sharedPrefs.getString(PreferenceKeys.OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES, "")!! .splitToSequence('\n') .filter { it.isNotBlank() && it.first() != '.' && it.last() != '.' } } diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSaveActivity.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSaveActivity.kt index 745d2d1e..f6ef8757 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSaveActivity.kt +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSaveActivity.kt @@ -100,7 +100,7 @@ class AutofillSaveActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - val repo = PasswordRepository.getRepositoryDirectory(applicationContext) + val repo = PasswordRepository.getRepositoryDirectory() val saveIntent = Intent(this, PasswordCreationActivity::class.java).apply { putExtras( bundleOf( diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt b/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt index ec8e7f9b..c7648f55 100644 --- a/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt +++ b/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt @@ -27,6 +27,7 @@ import com.zeapo.pwdstore.R import com.zeapo.pwdstore.utils.OPENPGP_PROVIDER import com.zeapo.pwdstore.utils.PreferenceKeys import com.zeapo.pwdstore.utils.clipboard +import com.zeapo.pwdstore.utils.sharedPrefs import com.zeapo.pwdstore.utils.snackbar import java.io.File import me.msfjarvis.openpgpktx.util.OpenPgpApi @@ -69,7 +70,7 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou /** * [SharedPreferences] instance used by subclasses to persist settings */ - val settings: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(this) } + val settings: SharedPreferences by lazy { sharedPrefs } /** * Handle to the [OpenPgpApi] instance that is used by subclasses to interface with OpenKeychain. diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt b/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt index d46f0a4e..177e1499 100644 --- a/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt +++ b/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt @@ -304,7 +304,7 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB data.action = OpenPgpApi.ACTION_ENCRYPT // pass enters the key ID into `.gpg-id`. - val repoRoot = PasswordRepository.getRepositoryDirectory(applicationContext) + val repoRoot = PasswordRepository.getRepositoryDirectory() val gpgIdentifierFile = File(repoRoot, directory.text.toString()).findTillRoot(".gpg-id", repoRoot) if (gpgIdentifierFile == null) { snackbar(message = resources.getString(R.string.failed_to_find_key_id)) @@ -391,7 +391,7 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB return@executeApiAsync } - if (!isInsideRepository(file)) { + if (!file.isInsideRepository()) { snackbar(message = getString(R.string.message_error_destination_outside_repo)) return@executeApiAsync } diff --git a/app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt b/app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt index 706592fe..06f85d1b 100644 --- a/app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt +++ b/app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt @@ -13,7 +13,6 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.content.edit import androidx.core.text.isDigitsOnly import androidx.lifecycle.lifecycleScope -import androidx.preference.PreferenceManager import com.github.ajalt.timberkt.Timber.tag import com.github.ajalt.timberkt.e import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -31,6 +30,7 @@ import com.zeapo.pwdstore.git.operation.SyncOperation import com.zeapo.pwdstore.utils.PasswordRepository import com.zeapo.pwdstore.utils.PreferenceKeys import com.zeapo.pwdstore.utils.getEncryptedPrefs +import com.zeapo.pwdstore.utils.sharedPrefs import java.io.File import java.net.URI import kotlinx.coroutines.launch @@ -61,7 +61,7 @@ abstract class BaseGitActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - settings = PreferenceManager.getDefaultSharedPreferences(this) + settings = sharedPrefs encryptedSettings = getEncryptedPrefs("git_operation") protocol = Protocol.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_PROTOCOL, null)) connectionMode = ConnectionMode.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_AUTH, null)) @@ -197,7 +197,7 @@ abstract class BaseGitActivity : AppCompatActivity() { return } - val localDir = requireNotNull(PasswordRepository.getRepositoryDirectory(this)) + val localDir = requireNotNull(PasswordRepository.getRepositoryDirectory()) val op = when (operation) { REQUEST_CLONE, GitOperation.GET_SSH_KEY_FROM_CLONE -> CloneOperation(localDir, url!!, this) REQUEST_PULL -> PullOperation(localDir, this) diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitConfigActivity.kt b/app/src/main/java/com/zeapo/pwdstore/git/GitConfigActivity.kt index 35a3c648..e84c87e1 100644 --- a/app/src/main/java/com/zeapo/pwdstore/git/GitConfigActivity.kt +++ b/app/src/main/java/com/zeapo/pwdstore/git/GitConfigActivity.kt @@ -34,7 +34,7 @@ class GitConfigActivity : BaseGitActivity() { else binding.gitUserName.setText(username) binding.gitUserEmail.setText(email) - val repo = PasswordRepository.getRepository(PasswordRepository.getRepositoryDirectory(this)) + val repo = PasswordRepository.getRepository(PasswordRepository.getRepositoryDirectory()) if (repo != null) { try { val objectId = repo.resolve(Constants.HEAD) diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt b/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt index 4830b2c8..3fe0314a 100644 --- a/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt +++ b/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt @@ -113,7 +113,7 @@ class GitServerConfigActivity : BaseGitActivity() { binding.saveButton.setOnClickListener { if (isClone && PasswordRepository.getRepository(null) == null) - PasswordRepository.initialize(this) + PasswordRepository.initialize() when (val result = updateUrl()) { GitUpdateUrlResult.Ok -> { settings.edit { @@ -161,7 +161,7 @@ class GitServerConfigActivity : BaseGitActivity() { * Clones the repository, the directory exists, deletes it */ private fun cloneRepository() { - val localDir = requireNotNull(PasswordRepository.getRepositoryDirectory(this)) + val localDir = requireNotNull(PasswordRepository.getRepositoryDirectory()) val localDirFiles = localDir.listFiles() ?: emptyArray() // Warn if non-empty folder unless it's a just-initialized store that has just a .git folder if (localDir.exists() && localDirFiles.isNotEmpty() && diff --git a/app/src/main/java/com/zeapo/pwdstore/git/operation/GitOperation.kt b/app/src/main/java/com/zeapo/pwdstore/git/operation/GitOperation.kt index 45fefd64..591c121f 100644 --- a/app/src/main/java/com/zeapo/pwdstore/git/operation/GitOperation.kt +++ b/app/src/main/java/com/zeapo/pwdstore/git/operation/GitOperation.kt @@ -158,9 +158,7 @@ abstract class GitOperation(gitDir: File, internal val callingActivity: Fragment .edit { remove(PreferenceKeys.SSH_OPENKEYSTORE_KEYID) } } is SshjSessionFactory -> { - callingActivity.applicationContext - .getEncryptedPrefs("git_operation") - .edit { + callingActivity.getEncryptedPrefs("git_operation").edit { remove(PreferenceKeys.SSH_KEY_LOCAL_PASSPHRASE) remove(PreferenceKeys.HTTPS_PASSWORD) } diff --git a/app/src/main/java/com/zeapo/pwdstore/pwgenxkpwd/XkpwdDictionary.kt b/app/src/main/java/com/zeapo/pwdstore/pwgenxkpwd/XkpwdDictionary.kt index 6f8a5129..3edaa5da 100644 --- a/app/src/main/java/com/zeapo/pwdstore/pwgenxkpwd/XkpwdDictionary.kt +++ b/app/src/main/java/com/zeapo/pwdstore/pwgenxkpwd/XkpwdDictionary.kt @@ -8,6 +8,7 @@ import android.content.Context import androidx.preference.PreferenceManager import com.zeapo.pwdstore.R import com.zeapo.pwdstore.utils.PreferenceKeys +import com.zeapo.pwdstore.utils.sharedPrefs import java.io.File class XkpwdDictionary(context: Context) { @@ -15,7 +16,7 @@ class XkpwdDictionary(context: Context) { val words: Map> init { - val prefs = PreferenceManager.getDefaultSharedPreferences(context) + val prefs = context.sharedPrefs val uri = prefs.getString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, "")!! val customDictFile = File(context.filesDir, XKPWD_CUSTOM_DICT_FILE) diff --git a/app/src/main/java/com/zeapo/pwdstore/sshkeygen/SshKeyGenActivity.kt b/app/src/main/java/com/zeapo/pwdstore/sshkeygen/SshKeyGenActivity.kt index 9de7bbfd..d4d76738 100644 --- a/app/src/main/java/com/zeapo/pwdstore/sshkeygen/SshKeyGenActivity.kt +++ b/app/src/main/java/com/zeapo/pwdstore/sshkeygen/SshKeyGenActivity.kt @@ -19,6 +19,7 @@ import com.jcraft.jsch.KeyPair import com.zeapo.pwdstore.R import com.zeapo.pwdstore.databinding.ActivitySshKeygenBinding import com.zeapo.pwdstore.utils.getEncryptedPrefs +import com.zeapo.pwdstore.utils.sharedPrefs import com.zeapo.pwdstore.utils.viewBinding import java.io.File import java.io.FileOutputStream @@ -91,8 +92,7 @@ class SshKeyGenActivity : AppCompatActivity() { if (e == null) { val df = ShowSshKeyFragment() df.show(supportFragmentManager, "public_key") - val prefs = PreferenceManager.getDefaultSharedPreferences(this) - prefs.edit { putBoolean("use_generated_key", true) } + sharedPrefs.edit { putBoolean("use_generated_key", true) } } else { MaterialAlertDialogBuilder(this) .setTitle(getString(R.string.error_generate_ssh_key)) diff --git a/app/src/main/java/com/zeapo/pwdstore/ui/adapters/PasswordItemRecyclerAdapter.kt b/app/src/main/java/com/zeapo/pwdstore/ui/adapters/PasswordItemRecyclerAdapter.kt index 4e153b88..9d5487ab 100644 --- a/app/src/main/java/com/zeapo/pwdstore/ui/adapters/PasswordItemRecyclerAdapter.kt +++ b/app/src/main/java/com/zeapo/pwdstore/ui/adapters/PasswordItemRecyclerAdapter.kt @@ -19,6 +19,7 @@ import com.zeapo.pwdstore.SearchableRepositoryAdapter import com.zeapo.pwdstore.stableId import com.zeapo.pwdstore.utils.PasswordItem import com.zeapo.pwdstore.utils.PreferenceKeys +import com.zeapo.pwdstore.utils.sharedPrefs import java.io.File open class PasswordItemRecyclerAdapter : @@ -49,8 +50,7 @@ open class PasswordItemRecyclerAdapter : lateinit var itemDetails: ItemDetailsLookup.ItemDetails fun bind(item: PasswordItem) { - val settings = - PreferenceManager.getDefaultSharedPreferences(itemView.context.applicationContext) + val settings = itemView.context.sharedPrefs val showHidden = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false) val parentPath = item.fullPathToParent.replace("(^/)|(/$)".toRegex(), "") val source = if (parentPath.isNotEmpty()) { diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt b/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt index 6ce45fe5..b5cb4f8c 100644 --- a/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt +++ b/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt @@ -18,6 +18,7 @@ import androidx.annotation.RequiresApi import androidx.appcompat.app.AlertDialog import androidx.core.content.getSystemService import androidx.fragment.app.FragmentActivity +import androidx.preference.PreferenceManager import androidx.security.crypto.EncryptedSharedPreferences import androidx.security.crypto.MasterKey import com.github.ajalt.timberkt.d @@ -97,6 +98,9 @@ fun Context.getEncryptedPrefs(fileName: String): SharedPreferences { ) } +val Context.sharedPrefs: SharedPreferences + get() = PreferenceManager.getDefaultSharedPreferences(applicationContext) + suspend fun FragmentActivity.commitChange( message: String, finishWithResultOnEnd: Intent? = null, @@ -109,7 +113,7 @@ suspend fun FragmentActivity.commitChange( } return } - object : GitOperation(getRepositoryDirectory(this@commitChange), this@commitChange) { + object : GitOperation(getRepositoryDirectory(), this@commitChange) { override val commands = arrayOf( git.add().addFilepattern("."), git.status(), @@ -151,6 +155,6 @@ val Context.autofillManager: AutofillManager? @RequiresApi(Build.VERSION_CODES.O) get() = getSystemService() -fun FragmentActivity.isInsideRepository(file: File): Boolean { - return file.canonicalPath.contains(getRepositoryDirectory(this).canonicalPath) +fun File.isInsideRepository(): Boolean { + return canonicalPath.contains(getRepositoryDirectory().canonicalPath) } diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.kt b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.kt index cb30ca2c..e07f30f2 100644 --- a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.kt +++ b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.kt @@ -4,10 +4,9 @@ */ package com.zeapo.pwdstore.utils -import android.content.Context import android.content.SharedPreferences import androidx.core.content.edit -import androidx.preference.PreferenceManager +import com.zeapo.pwdstore.Application import java.io.File import java.io.FileFilter import java.util.Comparator @@ -49,7 +48,9 @@ open class PasswordRepository protected constructor() { companion object { private var repository: Repository? = null - private lateinit var settings: SharedPreferences + private val settings by lazy { Application.instance.sharedPrefs } + private val filesDir + get() = Application.instance.filesDir /** * Returns the git repository @@ -152,27 +153,21 @@ open class PasswordRepository protected constructor() { } @JvmStatic - fun getRepositoryDirectory(context: Context): File { - if (!::settings.isInitialized) { - settings = PreferenceManager.getDefaultSharedPreferences(context.applicationContext) - } + fun getRepositoryDirectory(): File { return if (settings.getBoolean(PreferenceKeys.GIT_EXTERNAL, false)) { val externalRepo = settings.getString(PreferenceKeys.GIT_EXTERNAL_REPO, null) if (externalRepo != null) File(externalRepo) else - File(context.filesDir.toString(), "/store") + File(filesDir.toString(), "/store") } else { - File(context.filesDir.toString(), "/store") + File(filesDir.toString(), "/store") } } @JvmStatic - fun initialize(context: Context): Repository? { - if (!::settings.isInitialized) { - settings = PreferenceManager.getDefaultSharedPreferences(context.applicationContext) - } - val dir = getRepositoryDirectory(context) + fun initialize(): Repository? { + val dir = getRepositoryDirectory() // uninitialize the repo if the dir does not exist or is absolutely empty settings.edit { if (!dir.exists() || !dir.isDirectory || dir.listFiles()!!.isEmpty()) { -- cgit v1.2.3