Remove support for external storage and raise target SDK to 31 (#1863)
This commit is contained in:
parent
545da8f79b
commit
493e869022
17 changed files with 161 additions and 517 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
android:installLocation="auto">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<!-- Required by Autofill to verify the certificate hashes of packages -->
|
||||
<uses-permission
|
||||
android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||
tools:ignore="QueryAllPackagesPermission" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
|
@ -23,23 +24,28 @@
|
|||
<application
|
||||
android:name="dev.msfjarvis.aps.Application"
|
||||
android:allowBackup="false"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_content"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppThemeM3"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
tools:ignore="GoogleAppIndexingWarning"
|
||||
tools:targetApi="s">
|
||||
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.passwords.PasswordStore"
|
||||
android:configChanges="orientation|screenSize" />
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:exported="false" />
|
||||
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.onboarding.activity.OnboardingActivity"
|
||||
android:configChanges="orientation|screenSize" />
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:exported="false" />
|
||||
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.proxy.ProxySelectorActivity"
|
||||
android:exported="false"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
|
||||
<activity
|
||||
|
@ -60,6 +66,7 @@
|
|||
<activity
|
||||
android:name="com.journeyapps.barcodescanner.CaptureActivity"
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:exported="false"
|
||||
android:stateNotNeeded="true"
|
||||
android:theme="@style/zxing_CaptureTheme"
|
||||
android:windowSoftInputMode="stateAlwaysHidden"
|
||||
|
@ -67,50 +74,56 @@
|
|||
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.git.config.GitServerConfigActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_git_clone"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.git.config.GitConfigActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_git_config"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.git.log.GitLogActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_git_log" />
|
||||
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.settings.SettingsActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/action_settings"
|
||||
android:parentActivityName=".ui.passwords.PasswordStore" />
|
||||
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.settings.DirectorySelectionActivity"
|
||||
android:theme="@style/NoBackgroundThemeM3" />
|
||||
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.crypto.PasswordCreationActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/new_password_title"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.crypto.PasswordCreationActivityV2"
|
||||
android:exported="false"
|
||||
android:label="@string/new_password_title"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.crypto.DecryptActivity"
|
||||
android:exported="false"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.crypto.GetKeyIdsActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/NoBackgroundThemeM3" />
|
||||
|
||||
<service
|
||||
android:name="dev.msfjarvis.aps.util.services.ClipboardService"
|
||||
android:exported="false"
|
||||
android:process=":clipboard_service_process" />
|
||||
<service
|
||||
android:name="dev.msfjarvis.aps.util.services.PasswordExportService"
|
||||
android:exported="false"
|
||||
android:process=":password_export_service_process" />
|
||||
<service
|
||||
android:name="dev.msfjarvis.aps.util.services.OreoAutofillService"
|
||||
|
@ -124,41 +137,66 @@
|
|||
android:resource="@xml/oreo_autofill_service" />
|
||||
</service>
|
||||
|
||||
<activity android:name="dev.msfjarvis.aps.ui.folderselect.SelectFolderActivity" />
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.folderselect.SelectFolderActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.sshkeygen.SshKeyImportActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/NoBackgroundThemeM3"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.sshkeygen.SshKeyGenActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/pref_ssh_keygen_title"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.autofill.AutofillDecryptActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/NoBackgroundThemeM3" />
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.autofill.AutofillDecryptActivityV2"
|
||||
android:exported="false"
|
||||
android:theme="@style/NoBackgroundThemeM3" />
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.autofill.AutofillFilterView"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="false"
|
||||
android:theme="@style/DialogLikeThemeM3"
|
||||
android:windowSoftInputMode="adjustNothing" />
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.autofill.AutofillSaveActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/NoBackgroundThemeM3" />
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.autofill.oreo.ui.AutofillSmsActivity"
|
||||
android:configChanges="orientation"
|
||||
android:exported="false"
|
||||
android:theme="@style/DialogLikeThemeM3"
|
||||
android:windowSoftInputMode="adjustNothing" />
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.autofill.AutofillPublisherChangedActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="false"
|
||||
android:theme="@style/DialogLikeThemeM3"
|
||||
android:windowSoftInputMode="adjustNothing" />
|
||||
<activity android:name="dev.msfjarvis.aps.ui.pgp.PGPKeyImportActivity"
|
||||
<activity
|
||||
android:name="dev.msfjarvis.aps.ui.pgp.PGPKeyImportActivity"
|
||||
android:theme="@style/NoBackgroundThemeM3" />
|
||||
</application>
|
||||
|
||||
<queries>
|
||||
<package android:name="org.sufficientlysecure.keychain" />
|
||||
|
||||
<intent>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="https" />
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -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? {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
if (settings.getBoolean(PreferenceKeys.SEARCH_ON_START, false) && ::searchItem.isInitialized) {
|
||||
if (!searchItem.isActionViewExpanded) {
|
||||
searchItem.expandActionView()
|
||||
|
@ -362,34 +345,10 @@ 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 {
|
||||
PasswordRepository.initialize()
|
||||
checkLocalRepository(PasswordRepository.getRepositoryDirectory())
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkLocalRepository(localDir: File?) {
|
||||
if (localDir != null && settings.getBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false)) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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,11 +150,9 @@ 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)
|
||||
|
@ -185,9 +171,7 @@ class RepositorySettings(private val activity: FragmentActivity) : SettingsProvi
|
|||
removeDynamicShortcuts(dynamicShortcuts.map { it.id }.toMutableList())
|
||||
}
|
||||
}
|
||||
activity.sharedPrefs.edit {
|
||||
putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false)
|
||||
}
|
||||
activity.sharedPrefs.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false) }
|
||||
dialogInterface.cancel()
|
||||
activity.finish()
|
||||
}
|
||||
|
@ -198,31 +182,6 @@ class RepositorySettings(private val activity: FragmentActivity) : SettingsProvi
|
|||
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
|
||||
onClick {
|
||||
selectExternalGitRepository()
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
<!--
|
||||
~ Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
|
||||
~ SPDX-License-Identifier: GPL-3.0-only
|
||||
-->
|
||||
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:attr/colorBackground">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="@dimen/onboarding_icon_margin_top"
|
||||
android:contentDescription="@string/app_icon_hint"
|
||||
android:src="@mipmap/ic_launcher"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginStart="@dimen/fab_compat_margin"
|
||||
android:layout_marginEnd="@dimen/fab_compat_margin"
|
||||
android:text="@string/app_name"
|
||||
android:textAppearance="?attr/textAppearanceTitleLarge"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="@id/app_icon"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/app_icon"
|
||||
app:layout_constraintTop_toTopOf="@+id/app_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/repo_location"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="48dp"
|
||||
android:layout_marginEnd="@dimen/fab_compat_margin"
|
||||
android:text="@string/repository_n_location"
|
||||
android:textAppearance="?attr/textAppearanceHeadlineSmall"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/app_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/app_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/repo_location_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/onboarding_desc_margin_top"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@string/location_dialog_create_text"
|
||||
android:textAppearance="?attr/textAppearanceHeadlineSmall"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/repo_location"
|
||||
app:layout_constraintTop_toBottomOf="@id/repo_location" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/hidden"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="@dimen/onboarding_button_margin_top"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:maxWidth="300dp"
|
||||
android:minWidth="100dp"
|
||||
android:text="@string/location_hidden"
|
||||
app:layout_constraintBottom_toTopOf="@id/sdcard"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/repo_location_text" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/sdcard"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="128dp"
|
||||
android:maxWidth="300dp"
|
||||
android:minWidth="100dp"
|
||||
android:text="@string/location_sdcard"
|
||||
app:layout_constraintEnd_toEndOf="@id/hidden"
|
||||
app:layout_constraintStart_toStartOf="@id/hidden"
|
||||
app:layout_constraintTop_toBottomOf="@id/hidden" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
2
app/src/main/res/xml/backup_content.xml
Normal file
2
app/src/main/res/xml/backup_content.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<full-backup-content />
|
5
app/src/main/res/xml/data_extraction_rules.xml
Normal file
5
app/src/main/res/xml/data_extraction_rules.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<data-extraction-rules>
|
||||
<cloud-backup />
|
||||
<device-transfer />
|
||||
</data-extraction-rules>
|
|
@ -83,7 +83,7 @@ class AutofillSmsActivity : AppCompatActivity() {
|
|||
context,
|
||||
fillOtpFromSmsRequestCode++,
|
||||
intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT
|
||||
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
.intentSender
|
||||
}
|
||||
|
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -244,7 +244,7 @@ private fun getBrowserAutofillSupportLevel(
|
|||
public fun getInstalledBrowsersWithAutofillSupportLevel(
|
||||
context: Context
|
||||
): List<Pair<String, BrowserAutofillSupportLevel>> {
|
||||
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
|
||||
|
|
|
@ -11,7 +11,7 @@ extensions.configure<TestedExtension> {
|
|||
setCompileSdkVersion(31)
|
||||
defaultConfig {
|
||||
minSdk = 23
|
||||
targetSdk = 29
|
||||
targetSdk = 31
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
|
Loading…
Reference in a new issue