diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4142ce74..1c89d1bb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -40,6 +40,7 @@ All notable changes to this project will be documented in this file.
- Using HTTPS without authentication is now fully supported, and no longer asks for a username
- Enabling 'Show hidden files and folders' no longer shows Git-related files and folders
- XkPasswd password generator has been removed in favor of one backed by [Diceware](https://theworld.com/~reinhold/diceware.html)
+- Support for stores outside the hidden app directory has been removed due to technical restrictions, see [this issue](https://msfjarvis.dev/aps/issue/1849) for details.
## [1.13.5] - 2021-07-28
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ce40be47..aed314aa 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -8,10 +8,11 @@
android:installLocation="auto">
-
-
-
+
+
+ tools:ignore="GoogleAppIndexingWarning"
+ tools:targetApi="s">
+ android:configChanges="orientation|screenSize"
+ android:exported="false" />
+ android:configChanges="orientation|screenSize"
+ android:exported="false" />
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/dev/msfjarvis/aps/data/repo/PasswordRepository.kt b/app/src/main/java/dev/msfjarvis/aps/data/repo/PasswordRepository.kt
index a3cf2dda..9bf1bce6 100644
--- a/app/src/main/java/dev/msfjarvis/aps/data/repo/PasswordRepository.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/data/repo/PasswordRepository.kt
@@ -10,7 +10,6 @@ import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.runCatching
import dev.msfjarvis.aps.Application
import dev.msfjarvis.aps.data.password.PasswordItem
-import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.extensions.unsafeLazy
import dev.msfjarvis.aps.util.settings.PasswordSortOrder
@@ -106,12 +105,7 @@ object PasswordRepository {
}
fun getRepositoryDirectory(): File {
- return if (settings.getBoolean(PreferenceKeys.GIT_EXTERNAL, false)) {
- val externalRepo = settings.getString(PreferenceKeys.GIT_EXTERNAL_REPO)
- if (externalRepo != null) File(externalRepo) else File(filesDir.toString(), "/store")
- } else {
- File(filesDir.toString(), "/store")
- }
+ return File(filesDir.toString(), "/store")
}
fun initialize(): Repository? {
diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/onboarding/fragments/CloneFragment.kt b/app/src/main/java/dev/msfjarvis/aps/ui/onboarding/fragments/CloneFragment.kt
index 603c016b..16c1a784 100644
--- a/app/src/main/java/dev/msfjarvis/aps/ui/onboarding/fragments/CloneFragment.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/ui/onboarding/fragments/CloneFragment.kt
@@ -11,7 +11,10 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.edit
import androidx.fragment.app.Fragment
+import com.github.michaelbull.result.onFailure
+import com.github.michaelbull.result.runCatching
import dev.msfjarvis.aps.R
+import dev.msfjarvis.aps.data.repo.PasswordRepository
import dev.msfjarvis.aps.databinding.FragmentCloneBinding
import dev.msfjarvis.aps.ui.git.config.GitServerConfigActivity
import dev.msfjarvis.aps.util.extensions.finish
@@ -20,6 +23,9 @@ import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.extensions.unsafeLazy
import dev.msfjarvis.aps.util.extensions.viewBinding
import dev.msfjarvis.aps.util.settings.PreferenceKeys
+import logcat.LogPriority.ERROR
+import logcat.asLog
+import logcat.logcat
class CloneFragment : Fragment(R.layout.fragment_clone) {
@@ -38,17 +44,33 @@ class CloneFragment : Fragment(R.layout.fragment_clone) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.cloneRemote.setOnClickListener { cloneToHiddenDir() }
- binding.createLocal.setOnClickListener {
- parentFragmentManager.performTransactionWithBackStack(RepoLocationFragment.newInstance())
- }
+ binding.createLocal.setOnClickListener { createRepository() }
}
/** Clones a remote Git repository to the app's private directory */
private fun cloneToHiddenDir() {
- settings.edit { putBoolean(PreferenceKeys.GIT_EXTERNAL, false) }
cloneAction.launch(GitServerConfigActivity.createCloneIntent(requireContext()))
}
+ private fun createRepository() {
+ val localDir = PasswordRepository.getRepositoryDirectory()
+ runCatching {
+ check(localDir.exists() || localDir.mkdir()) { "Failed to create directory!" }
+ PasswordRepository.createRepository(localDir)
+ if (!PasswordRepository.isInitialized) {
+ PasswordRepository.initialize()
+ }
+ parentFragmentManager.performTransactionWithBackStack(KeySelectionFragment.newInstance())
+ }
+ .onFailure { e ->
+ logcat(ERROR) { e.asLog() }
+ if (!localDir.delete()) {
+ logcat { "Failed to delete local repository: $localDir" }
+ }
+ finish()
+ }
+ }
+
companion object {
fun newInstance(): CloneFragment = CloneFragment()
diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/onboarding/fragments/RepoLocationFragment.kt b/app/src/main/java/dev/msfjarvis/aps/ui/onboarding/fragments/RepoLocationFragment.kt
deleted file mode 100644
index befe44f1..00000000
--- a/app/src/main/java/dev/msfjarvis/aps/ui/onboarding/fragments/RepoLocationFragment.kt
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-
-package dev.msfjarvis.aps.ui.onboarding.fragments
-
-import android.Manifest
-import android.content.Intent
-import android.os.Bundle
-import android.view.View
-import androidx.activity.result.contract.ActivityResultContracts
-import androidx.appcompat.app.AppCompatActivity
-import androidx.core.content.edit
-import androidx.fragment.app.Fragment
-import com.github.michaelbull.result.onFailure
-import com.github.michaelbull.result.runCatching
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import dev.msfjarvis.aps.R
-import dev.msfjarvis.aps.data.repo.PasswordRepository
-import dev.msfjarvis.aps.databinding.FragmentRepoLocationBinding
-import dev.msfjarvis.aps.ui.settings.DirectorySelectionActivity
-import dev.msfjarvis.aps.util.extensions.finish
-import dev.msfjarvis.aps.util.extensions.getString
-import dev.msfjarvis.aps.util.extensions.isPermissionGranted
-import dev.msfjarvis.aps.util.extensions.listFilesRecursively
-import dev.msfjarvis.aps.util.extensions.performTransactionWithBackStack
-import dev.msfjarvis.aps.util.extensions.sharedPrefs
-import dev.msfjarvis.aps.util.extensions.unsafeLazy
-import dev.msfjarvis.aps.util.extensions.viewBinding
-import dev.msfjarvis.aps.util.settings.PasswordSortOrder
-import dev.msfjarvis.aps.util.settings.PreferenceKeys
-import java.io.File
-import logcat.LogPriority.ERROR
-import logcat.asLog
-import logcat.logcat
-
-class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
-
- private val settings by unsafeLazy { requireActivity().applicationContext.sharedPrefs }
- private val directorySelectIntent by unsafeLazy {
- Intent(requireContext(), DirectorySelectionActivity::class.java)
- }
- private val binding by viewBinding(FragmentRepoLocationBinding::bind)
- private val sortOrder: PasswordSortOrder
- get() = PasswordSortOrder.getSortOrder(settings)
-
- private val repositoryInitAction =
- registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
- if (result.resultCode == AppCompatActivity.RESULT_OK) {
- initializeRepositoryInfo()
- }
- }
-
- private val externalDirectorySelectAction =
- registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
- if (result.resultCode == AppCompatActivity.RESULT_OK) {
- if (checkExternalDirectory()) {
- finish()
- } else {
- createRepository()
- }
- }
- }
-
- private val externalDirPermGrantedAction = createPermGrantedAction {
- externalDirectorySelectAction.launch(directorySelectIntent)
- }
-
- private val repositoryUsePermGrantedAction = createPermGrantedAction {
- initializeRepositoryInfo()
- }
-
- private val repositoryChangePermGrantedAction = createPermGrantedAction {
- repositoryInitAction.launch(directorySelectIntent)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- binding.hidden.setOnClickListener { createRepoInHiddenDir() }
-
- binding.sdcard.setOnClickListener { createRepoFromExternalDir() }
- }
-
- /** Initializes an empty repository in the app's private directory */
- private fun createRepoInHiddenDir() {
- settings.edit {
- putBoolean(PreferenceKeys.GIT_EXTERNAL, false)
- remove(PreferenceKeys.GIT_EXTERNAL_REPO)
- }
- initializeRepositoryInfo()
- }
-
- /** Initializes an empty repository in a selected directory if one does not already exist */
- private fun createRepoFromExternalDir() {
- settings.edit { putBoolean(PreferenceKeys.GIT_EXTERNAL, true) }
- val externalRepo = settings.getString(PreferenceKeys.GIT_EXTERNAL_REPO)
- if (externalRepo == null) {
- if (!isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
- externalDirPermGrantedAction.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- } else {
- // Unlikely we have storage permissions without user ever selecting a directory,
- // but let's not assume.
- externalDirectorySelectAction.launch(directorySelectIntent)
- }
- } else {
- MaterialAlertDialogBuilder(requireActivity())
- .setTitle(resources.getString(R.string.directory_selected_title))
- .setMessage(resources.getString(R.string.directory_selected_message, externalRepo))
- .setPositiveButton(resources.getString(R.string.use)) { _, _ ->
- if (!isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
- repositoryUsePermGrantedAction.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- } else {
- initializeRepositoryInfo()
- }
- }
- .setNegativeButton(resources.getString(R.string.change)) { _, _ ->
- if (!isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
- repositoryChangePermGrantedAction.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- } else {
- repositoryInitAction.launch(directorySelectIntent)
- }
- }
- .show()
- }
- }
-
- private fun checkExternalDirectory(): Boolean {
- if (settings.getBoolean(PreferenceKeys.GIT_EXTERNAL, false) &&
- settings.getString(PreferenceKeys.GIT_EXTERNAL_REPO) != null
- ) {
- val externalRepoPath = settings.getString(PreferenceKeys.GIT_EXTERNAL_REPO)
- val dir = externalRepoPath?.let { File(it) }
- if (dir != null && // The directory could be opened
- dir.exists() && // The directory exists
- dir.isDirectory && // The directory, is really a directory
- dir.listFilesRecursively().isNotEmpty() && // The directory contains files
- // The directory contains a non-zero number of password files
- PasswordRepository.getPasswords(
- dir,
- PasswordRepository.getRepositoryDirectory(),
- sortOrder
- )
- .isNotEmpty()
- ) {
- PasswordRepository.closeRepository()
- return true
- }
- }
- return false
- }
-
- private fun createRepository() {
- val localDir = PasswordRepository.getRepositoryDirectory()
- runCatching {
- check(localDir.exists() || localDir.mkdir()) { "Failed to create directory!" }
- PasswordRepository.createRepository(localDir)
- if (!PasswordRepository.isInitialized) {
- PasswordRepository.initialize()
- }
- parentFragmentManager.performTransactionWithBackStack(KeySelectionFragment.newInstance())
- }
- .onFailure { e ->
- logcat(ERROR) { e.asLog() }
- if (!localDir.delete()) {
- logcat { "Failed to delete local repository: $localDir" }
- }
- finish()
- }
- }
-
- private fun initializeRepositoryInfo() {
- val externalRepo = settings.getBoolean(PreferenceKeys.GIT_EXTERNAL, false)
- val externalRepoPath = settings.getString(PreferenceKeys.GIT_EXTERNAL_REPO)
- if (externalRepo && !isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
- return
- }
- if (externalRepo && externalRepoPath != null) {
- if (checkExternalDirectory()) {
- finish()
- return
- }
- }
- createRepository()
- }
-
- private fun createPermGrantedAction(block: () -> Unit) =
- registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
- if (granted) {
- block.invoke()
- }
- }
-
- companion object {
-
- fun newInstance(): RepoLocationFragment = RepoLocationFragment()
- }
-}
diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt b/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt
index d80959b8..e4ec2359 100644
--- a/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/ui/passwords/PasswordStore.kt
@@ -4,7 +4,6 @@
*/
package dev.msfjarvis.aps.ui.passwords
-import android.Manifest
import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Context
@@ -40,12 +39,10 @@ import dev.msfjarvis.aps.ui.crypto.DecryptActivity
import dev.msfjarvis.aps.ui.crypto.DecryptActivityV2
import dev.msfjarvis.aps.ui.crypto.PasswordCreationActivity
import dev.msfjarvis.aps.ui.crypto.PasswordCreationActivityV2
-import dev.msfjarvis.aps.ui.dialogs.BasicBottomSheet
import dev.msfjarvis.aps.ui.dialogs.FolderCreationDialogFragment
import dev.msfjarvis.aps.ui.folderselect.SelectFolderActivity
import dev.msfjarvis.aps.ui.git.base.BaseGitActivity
import dev.msfjarvis.aps.ui.onboarding.activity.OnboardingActivity
-import dev.msfjarvis.aps.ui.settings.DirectorySelectionActivity
import dev.msfjarvis.aps.ui.settings.SettingsActivity
import dev.msfjarvis.aps.util.autofill.AutofillMatcher
import dev.msfjarvis.aps.util.extensions.base64
@@ -53,7 +50,6 @@ import dev.msfjarvis.aps.util.extensions.commitChange
import dev.msfjarvis.aps.util.extensions.contains
import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.extensions.isInsideRepository
-import dev.msfjarvis.aps.util.extensions.isPermissionGranted
import dev.msfjarvis.aps.util.extensions.listFilesRecursively
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.features.Feature
@@ -206,16 +202,7 @@ class PasswordStore : BaseGitActivity() {
@SuppressLint("NewApi")
override fun onCreate(savedInstanceState: Bundle?) {
- // If user opens app with permission granted then revokes and returns,
- // prevent attempt to create password list fragment
- var savedInstance = savedInstanceState
- if (savedInstanceState != null &&
- (!settings.getBoolean(PreferenceKeys.GIT_EXTERNAL, false) ||
- !isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE))
- ) {
- savedInstance = null
- }
- super.onCreate(savedInstance)
+ super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pwdstore)
model.currentDir.observe(this) { dir ->
@@ -233,11 +220,7 @@ class PasswordStore : BaseGitActivity() {
override fun onResume() {
super.onResume()
- if (settings.getBoolean(PreferenceKeys.GIT_EXTERNAL, false)) {
- hasRequiredStoragePermissions()
- } else {
- checkLocalRepository()
- }
+ checkLocalRepository()
if (settings.getBoolean(PreferenceKeys.SEARCH_ON_START, false) && ::searchItem.isInitialized) {
if (!searchItem.isActionViewExpanded) {
searchItem.expandActionView()
@@ -362,33 +345,9 @@ class PasswordStore : BaseGitActivity() {
)
}
- /**
- * Validates if storage permission is granted, and requests for it if not. The return value is
- * true if the permission has been granted.
- */
- private fun hasRequiredStoragePermissions(): Boolean {
- return if (!isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
- BasicBottomSheet.Builder(this)
- .setMessageRes(R.string.access_sdcard_text)
- .setPositiveButtonClickListener(getString(R.string.snackbar_action_grant)) {
- storagePermissionRequest.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- }
- .build()
- .show(supportFragmentManager, "STORAGE_PERMISSION_MISSING")
- false
- } else {
- checkLocalRepository()
- true
- }
- }
-
private fun checkLocalRepository() {
- val repo = PasswordRepository.initialize()
- if (repo == null) {
- directorySelectAction.launch(Intent(this, DirectorySelectionActivity::class.java))
- } else {
- checkLocalRepository(PasswordRepository.getRepositoryDirectory())
- }
+ PasswordRepository.initialize()
+ checkLocalRepository(PasswordRepository.getRepositoryDirectory())
}
private fun checkLocalRepository(localDir: File?) {
diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/settings/DirectorySelectionActivity.kt b/app/src/main/java/dev/msfjarvis/aps/ui/settings/DirectorySelectionActivity.kt
deleted file mode 100644
index 1f8873c0..00000000
--- a/app/src/main/java/dev/msfjarvis/aps/ui/settings/DirectorySelectionActivity.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-
-package dev.msfjarvis.aps.ui.settings
-
-import android.net.Uri
-import android.os.Bundle
-import android.os.Environment
-import android.provider.DocumentsContract
-import androidx.activity.result.contract.ActivityResultContracts
-import androidx.appcompat.app.AppCompatActivity
-import androidx.core.content.edit
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import dev.msfjarvis.aps.R
-import dev.msfjarvis.aps.util.extensions.sharedPrefs
-import dev.msfjarvis.aps.util.settings.PreferenceKeys
-import logcat.logcat
-
-class DirectorySelectionActivity : AppCompatActivity() {
-
- @Suppress("DEPRECATION")
- private val directorySelectAction =
- registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri: Uri? ->
- if (uri == null) return@registerForActivityResult
-
- logcat { "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 = sharedPrefs
-
- logcat { "Selected repository path is $repoPath" }
-
- if (Environment.getExternalStorageDirectory().path == repoPath) {
- MaterialAlertDialogBuilder(this)
- .setTitle(resources.getString(R.string.sdcard_root_warning_title))
- .setMessage(resources.getString(R.string.sdcard_root_warning_message))
- .setPositiveButton(resources.getString(R.string.sdcard_root_warning_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) }
- setResult(RESULT_OK)
- finish()
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- directorySelectAction.launch(null)
- }
-}
diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/settings/RepositorySettings.kt b/app/src/main/java/dev/msfjarvis/aps/ui/settings/RepositorySettings.kt
index cbd9c18f..1c43127a 100644
--- a/app/src/main/java/dev/msfjarvis/aps/ui/settings/RepositorySettings.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/ui/settings/RepositorySettings.kt
@@ -23,7 +23,6 @@ import dagger.hilt.components.SingletonComponent
import de.Maxr1998.modernpreferences.Preference
import de.Maxr1998.modernpreferences.PreferenceScreen
import de.Maxr1998.modernpreferences.helpers.checkBox
-import de.Maxr1998.modernpreferences.helpers.onCheckedChange
import de.Maxr1998.modernpreferences.helpers.onClick
import de.Maxr1998.modernpreferences.helpers.pref
import dev.msfjarvis.aps.R
@@ -60,17 +59,6 @@ class RepositorySettings(private val activity: FragmentActivity) : SettingsProvi
private var showSshKeyPref: Preference? = null
- private fun selectExternalGitRepository() {
- MaterialAlertDialogBuilder(activity)
- .setTitle(activity.resources.getString(R.string.external_repository_dialog_title))
- .setMessage(activity.resources.getString(R.string.external_repository_dialog_text))
- .setPositiveButton(R.string.dialog_ok) { _, _ ->
- activity.launchActivity(DirectorySelectionActivity::class.java)
- }
- .setNegativeButton(R.string.dialog_cancel, null)
- .show()
- }
-
override fun provideSettings(builder: PreferenceScreen.Builder) {
val encryptedPreferences = hiltEntryPoint.encryptedPreferences()
val gitSettings = hiltEntryPoint.gitSettings()
@@ -162,64 +150,35 @@ class RepositorySettings(private val activity: FragmentActivity) : SettingsProvi
true
}
}
- val deleteRepoPref =
- pref(PreferenceKeys.GIT_DELETE_REPO) {
- titleRes = R.string.pref_git_delete_repo_title
- summaryRes = R.string.pref_git_delete_repo_summary
- visible = !activity.sharedPrefs.getBoolean(PreferenceKeys.GIT_EXTERNAL, false)
- onClick {
- val repoDir = PasswordRepository.getRepositoryDirectory()
- MaterialAlertDialogBuilder(activity)
- .setTitle(R.string.pref_dialog_delete_title)
- .setMessage(activity.getString(R.string.dialog_delete_msg, repoDir))
- .setCancelable(false)
- .setPositiveButton(R.string.dialog_delete) { dialogInterface, _ ->
- runCatching {
- PasswordRepository.getRepositoryDirectory().deleteRecursively()
- PasswordRepository.closeRepository()
- }
- .onFailure { it.message?.let { message -> activity.snackbar(message = message) } }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
- activity.getSystemService()?.apply {
- removeDynamicShortcuts(dynamicShortcuts.map { it.id }.toMutableList())
- }
- }
- activity.sharedPrefs.edit {
- putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false)
- }
- dialogInterface.cancel()
- activity.finish()
- }
- .setNegativeButton(R.string.dialog_do_not_delete) { dialogInterface, _ ->
- run { dialogInterface.cancel() }
- }
- .show()
- true
- }
- }
- checkBox(PreferenceKeys.GIT_EXTERNAL) {
- titleRes = R.string.pref_external_repository_title
- summaryRes = R.string.pref_external_repository_summary
- onCheckedChange { checked ->
- deleteRepoPref.visible = !checked
- deleteRepoPref.requestRebind()
- PasswordRepository.closeRepository()
- activity.sharedPrefs.edit { putBoolean(PreferenceKeys.REPO_CHANGED, true) }
- true
- }
- }
- pref(PreferenceKeys.GIT_EXTERNAL_REPO) {
- val externalRepo = activity.sharedPrefs.getString(PreferenceKeys.GIT_EXTERNAL_REPO)
- if (externalRepo != null) {
- summary = externalRepo
- } else {
- summaryRes = R.string.pref_select_external_repository_summary_no_repo_selected
- }
- titleRes = R.string.pref_select_external_repository_title
- dependency = PreferenceKeys.GIT_EXTERNAL
+ pref(PreferenceKeys.GIT_DELETE_REPO) {
+ titleRes = R.string.pref_git_delete_repo_title
+ summaryRes = R.string.pref_git_delete_repo_summary
onClick {
- selectExternalGitRepository()
+ val repoDir = PasswordRepository.getRepositoryDirectory()
+ MaterialAlertDialogBuilder(activity)
+ .setTitle(R.string.pref_dialog_delete_title)
+ .setMessage(activity.getString(R.string.dialog_delete_msg, repoDir))
+ .setCancelable(false)
+ .setPositiveButton(R.string.dialog_delete) { dialogInterface, _ ->
+ runCatching {
+ PasswordRepository.getRepositoryDirectory().deleteRecursively()
+ PasswordRepository.closeRepository()
+ }
+ .onFailure { it.message?.let { message -> activity.snackbar(message = message) } }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
+ activity.getSystemService()?.apply {
+ removeDynamicShortcuts(dynamicShortcuts.map { it.id }.toMutableList())
+ }
+ }
+ activity.sharedPrefs.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false) }
+ dialogInterface.cancel()
+ activity.finish()
+ }
+ .setNegativeButton(R.string.dialog_do_not_delete) { dialogInterface, _ ->
+ run { dialogInterface.cancel() }
+ }
+ .show()
true
}
}
diff --git a/app/src/main/java/dev/msfjarvis/aps/util/settings/Migrations.kt b/app/src/main/java/dev/msfjarvis/aps/util/settings/Migrations.kt
index 5d61e75b..b90856b1 100644
--- a/app/src/main/java/dev/msfjarvis/aps/util/settings/Migrations.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/util/settings/Migrations.kt
@@ -26,6 +26,7 @@ fun runMigrations(filesDirPath: String, sharedPrefs: SharedPreferences, gitSetti
migrateToSshKey(filesDirPath, sharedPrefs)
migrateToClipboardHistory(sharedPrefs)
migrateToDiceware(sharedPrefs)
+ removeExternalStorageProperties(sharedPrefs)
}
private fun migrateToGitUrlBasedConfig(sharedPrefs: SharedPreferences, gitSettings: GitSettings) {
@@ -132,3 +133,18 @@ private fun migrateToDiceware(sharedPrefs: SharedPreferences) {
}
}
}
+
+private fun removeExternalStorageProperties(prefs: SharedPreferences) {
+ logcat(TAG, INFO) { "Removing preferences related to external storage" }
+ prefs.edit {
+ if (prefs.contains(PreferenceKeys.GIT_EXTERNAL)) {
+ if (prefs.getBoolean(PreferenceKeys.GIT_EXTERNAL, false)) {
+ putBoolean(PreferenceKeys.GIT_EXTERNAL_MIGRATED, true)
+ }
+ remove(PreferenceKeys.GIT_EXTERNAL)
+ }
+ if (prefs.contains(PreferenceKeys.GIT_EXTERNAL_REPO)) {
+ remove(PreferenceKeys.GIT_EXTERNAL_REPO)
+ }
+ }
+}
diff --git a/app/src/main/java/dev/msfjarvis/aps/util/settings/PreferenceKeys.kt b/app/src/main/java/dev/msfjarvis/aps/util/settings/PreferenceKeys.kt
index 6168cfee..152275d6 100644
--- a/app/src/main/java/dev/msfjarvis/aps/util/settings/PreferenceKeys.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/util/settings/PreferenceKeys.kt
@@ -8,7 +8,6 @@ package dev.msfjarvis.aps.util.settings
object PreferenceKeys {
const val APP_THEME = "app_theme"
- const val APP_VERSION = "app_version"
const val AUTOFILL_ENABLE = "autofill_enable"
const val BIOMETRIC_AUTH = "biometric_auth"
@Deprecated(
@@ -26,8 +25,11 @@ object PreferenceKeys {
const val GIT_CONFIG = "git_config"
const val GIT_CONFIG_AUTHOR_EMAIL = "git_config_user_email"
const val GIT_CONFIG_AUTHOR_NAME = "git_config_user_name"
+ @Deprecated(message = "We're removing support for external storage")
const val GIT_EXTERNAL = "git_external"
+ @Deprecated(message = "We're removing support for external storage")
const val GIT_EXTERNAL_REPO = "git_external_repo"
+ const val GIT_EXTERNAL_MIGRATED = "git_external_migrated"
const val GIT_REMOTE_AUTH = "git_remote_auth"
const val GIT_REMOTE_KEY_TYPE = "git_remote_key_type"
@@ -50,10 +52,7 @@ object PreferenceKeys {
const val OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES = "oreo_autofill_custom_public_suffixes"
const val OREO_AUTOFILL_DEFAULT_USERNAME = "oreo_autofill_default_username"
const val OREO_AUTOFILL_DIRECTORY_STRUCTURE = "oreo_autofill_directory_structure"
- const val PREF_KEY_CUSTOM_DICT = "pref_key_custom_dict"
- const val PREF_KEY_IS_CUSTOM_DICT = "pref_key_is_custom_dict"
const val PREF_KEY_PWGEN_TYPE = "pref_key_pwgen_type"
- const val PREF_SELECT_EXTERNAL = "pref_select_external"
const val REPOSITORY_INITIALIZED = "repository_initialized"
const val REPO_CHANGED = "repo_changed"
const val SEARCH_ON_START = "search_on_start"
diff --git a/app/src/main/res/layout/fragment_repo_location.xml b/app/src/main/res/layout/fragment_repo_location.xml
deleted file mode 100644
index 0302eaff..00000000
--- a/app/src/main/res/layout/fragment_repo_location.xml
+++ /dev/null
@@ -1,95 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/xml/backup_content.xml b/app/src/main/res/xml/backup_content.xml
new file mode 100644
index 00000000..1b0854f7
--- /dev/null
+++ b/app/src/main/res/xml/backup_content.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 00000000..2148d1dd
--- /dev/null
+++ b/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/nonFree/java/dev/msfjarvis/aps/autofill/oreo/ui/AutofillSmsActivity.kt b/app/src/nonFree/java/dev/msfjarvis/aps/autofill/oreo/ui/AutofillSmsActivity.kt
index abe855cd..4c751bb0 100644
--- a/app/src/nonFree/java/dev/msfjarvis/aps/autofill/oreo/ui/AutofillSmsActivity.kt
+++ b/app/src/nonFree/java/dev/msfjarvis/aps/autofill/oreo/ui/AutofillSmsActivity.kt
@@ -83,7 +83,7 @@ class AutofillSmsActivity : AppCompatActivity() {
context,
fillOtpFromSmsRequestCode++,
intent,
- PendingIntent.FLAG_CANCEL_CURRENT
+ PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
.intentSender
}
diff --git a/app/src/test/java/dev/msfjarvis/aps/util/settings/MigrationsTest.kt b/app/src/test/java/dev/msfjarvis/aps/util/settings/MigrationsTest.kt
index d279ab03..cf89d81e 100644
--- a/app/src/test/java/dev/msfjarvis/aps/util/settings/MigrationsTest.kt
+++ b/app/src/test/java/dev/msfjarvis/aps/util/settings/MigrationsTest.kt
@@ -16,6 +16,7 @@ import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNull
+import kotlin.test.assertTrue
import org.junit.Rule
import org.junit.rules.TemporaryFolder
@@ -50,7 +51,6 @@ class MigrationsTest {
@Test
fun verifySshWithCustomPortMigration() {
sharedPrefs.edit {
- clear()
putString(PreferenceKeys.GIT_REMOTE_PORT, "2200")
putString(PreferenceKeys.GIT_REMOTE_USERNAME, "msfjarvis")
putString(PreferenceKeys.GIT_REMOTE_LOCATION, "/mnt/disk3/pass-repo")
@@ -73,7 +73,6 @@ class MigrationsTest {
@Test
fun verifySshWithDefaultPortMigration() {
sharedPrefs.edit {
- clear()
putString(PreferenceKeys.GIT_REMOTE_USERNAME, "msfjarvis")
putString(PreferenceKeys.GIT_REMOTE_LOCATION, "/mnt/disk3/pass-repo")
putString(PreferenceKeys.GIT_REMOTE_SERVER, "192.168.0.102")
@@ -95,7 +94,6 @@ class MigrationsTest {
@Test
fun verifyHttpsWithGitHubMigration() {
sharedPrefs.edit {
- clear()
putString(PreferenceKeys.GIT_REMOTE_USERNAME, "msfjarvis")
putString(PreferenceKeys.GIT_REMOTE_LOCATION, "Android-Password-Store/pass-test")
putString(PreferenceKeys.GIT_REMOTE_SERVER, "github.com")
@@ -116,7 +114,6 @@ class MigrationsTest {
@Test
fun verifyHiddenFoldersMigrationIfDisabled() {
- sharedPrefs.edit { clear() }
runMigrations(
filesDir,
sharedPrefs,
@@ -128,10 +125,7 @@ class MigrationsTest {
@Test
fun verifyHiddenFoldersMigrationIfEnabled() {
- sharedPrefs.edit {
- clear()
- putBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, true)
- }
+ sharedPrefs.edit { putBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, true) }
runMigrations(
filesDir,
sharedPrefs,
@@ -143,10 +137,7 @@ class MigrationsTest {
@Test
fun verifyClearClipboardHistoryMigration() {
- sharedPrefs.edit {
- clear()
- putBoolean(PreferenceKeys.CLEAR_CLIPBOARD_20X, true)
- }
+ sharedPrefs.edit { putBoolean(PreferenceKeys.CLEAR_CLIPBOARD_20X, true) }
runMigrations(
filesDir,
sharedPrefs,
@@ -158,10 +149,7 @@ class MigrationsTest {
@Test
fun verifyClassicPasswordGeneratorMigration() {
- sharedPrefs.edit {
- clear()
- putString(PreferenceKeys.PREF_KEY_PWGEN_TYPE, "classic")
- }
+ sharedPrefs.edit { putString(PreferenceKeys.PREF_KEY_PWGEN_TYPE, "classic") }
runMigrations(
filesDir,
sharedPrefs,
@@ -172,10 +160,7 @@ class MigrationsTest {
@Test
fun verifyXkPasswdPasswordGeneratorMigration() {
- sharedPrefs.edit {
- clear()
- putString(PreferenceKeys.PREF_KEY_PWGEN_TYPE, "xkpasswd")
- }
+ sharedPrefs.edit { putString(PreferenceKeys.PREF_KEY_PWGEN_TYPE, "xkpasswd") }
runMigrations(
filesDir,
sharedPrefs,
@@ -183,4 +168,20 @@ class MigrationsTest {
)
assertEquals("diceware", sharedPrefs.getString(PreferenceKeys.PREF_KEY_PWGEN_TYPE))
}
+
+ @Test
+ fun verifyExternalStorageMigration() {
+ sharedPrefs.edit {
+ putBoolean(PreferenceKeys.GIT_EXTERNAL, true)
+ putString(PreferenceKeys.GIT_EXTERNAL_REPO, "/sdcard/")
+ }
+ runMigrations(
+ filesDir,
+ sharedPrefs,
+ GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir),
+ )
+ assertFalse { sharedPrefs.contains(PreferenceKeys.GIT_EXTERNAL) }
+ assertFalse { sharedPrefs.contains(PreferenceKeys.GIT_EXTERNAL_REPO) }
+ assertTrue { sharedPrefs.getBoolean(PreferenceKeys.GIT_EXTERNAL_MIGRATED, false) }
+ }
}
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FeatureAndTrustDetection.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FeatureAndTrustDetection.kt
index bd84746b..849113cf 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FeatureAndTrustDetection.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FeatureAndTrustDetection.kt
@@ -244,7 +244,7 @@ private fun getBrowserAutofillSupportLevel(
public fun getInstalledBrowsersWithAutofillSupportLevel(
context: Context
): List> {
- val testWebIntent = Intent(Intent.ACTION_VIEW).apply { data = Uri.parse("http://example.org") }
+ val testWebIntent = Intent(Intent.ACTION_VIEW).apply { data = Uri.parse("https://example.org") }
val installedBrowsers =
context.packageManager.queryIntentActivities(testWebIntent, PackageManager.MATCH_ALL)
return installedBrowsers
diff --git a/build-logic/android-plugins/src/main/kotlin/com.github.android-password-store.android-common.gradle.kts b/build-logic/android-plugins/src/main/kotlin/com.github.android-password-store.android-common.gradle.kts
index 9400acc2..c7bbf0fd 100644
--- a/build-logic/android-plugins/src/main/kotlin/com.github.android-password-store.android-common.gradle.kts
+++ b/build-logic/android-plugins/src/main/kotlin/com.github.android-password-store.android-common.gradle.kts
@@ -11,7 +11,7 @@ extensions.configure {
setCompileSdkVersion(31)
defaultConfig {
minSdk = 23
- targetSdk = 29
+ targetSdk = 31
}
sourceSets {