aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/src/main/AndroidManifest.xml3
-rw-r--r--app/src/main/java/app/passwordstore/Application.kt39
-rw-r--r--app/src/main/java/app/passwordstore/injection/AutofillResponseBuilderModule.kt11
-rw-r--r--app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt7
-rw-r--r--app/src/main/java/app/passwordstore/ui/autofill/AutofillFilterView.kt7
-rw-r--r--app/src/main/java/app/passwordstore/ui/autofill/AutofillPublisherChangedActivity.kt7
-rw-r--r--app/src/main/java/app/passwordstore/ui/crypto/CryptoExtensions.kt17
-rw-r--r--app/src/main/java/app/passwordstore/ui/editor/EditorViewModel.kt10
-rw-r--r--app/src/main/java/app/passwordstore/ui/settings/ProxyViewModel.kt6
-rw-r--r--app/src/main/java/app/passwordstore/util/auth/BiometricAuthenticator.kt9
-rw-r--r--app/src/main/java/app/passwordstore/util/autofill/Api26AutofillResponseBuilder.kt173
-rw-r--r--app/src/main/java/app/passwordstore/util/autofill/Api30AutofillResponseBuilder.kt1
-rw-r--r--app/src/main/java/app/passwordstore/util/autofill/AutofillResponseBuilder.kt11
-rw-r--r--app/src/main/java/app/passwordstore/util/autofill/AutofillViewUtils.kt11
-rw-r--r--app/src/main/java/app/passwordstore/util/crypto/KeystorePreferences.kt21
-rw-r--r--app/src/main/java/app/passwordstore/util/extensions/AndroidExtensions.kt2
-rw-r--r--app/src/main/java/app/passwordstore/util/git/sshj/SshKey.kt21
-rw-r--r--app/src/main/java/app/passwordstore/util/services/ClipboardService.kt7
-rw-r--r--app/src/main/java/app/passwordstore/util/services/OreoAutofillService.kt17
-rw-r--r--app/src/main/res/values-de/strings.xml2
-rw-r--r--app/src/main/res/values-fr/strings.xml2
-rw-r--r--app/src/main/res/values-gl/strings.xml2
-rw-r--r--app/src/main/res/values-it/strings.xml2
-rw-r--r--app/src/main/res/values-ko-rKR/strings.xml2
-rw-r--r--app/src/main/res/values-pl-rPL/strings.xml2
-rw-r--r--app/src/main/res/values-pt-rBR/strings.xml2
-rw-r--r--app/src/main/res/values-ru/strings.xml2
-rw-r--r--app/src/main/res/values-v29/arrays.xml17
-rw-r--r--app/src/main/res/values-v29/prefs.xml8
-rw-r--r--app/src/main/res/values-zh-rCN/strings.xml2
-rw-r--r--app/src/main/res/values/arrays.xml4
-rw-r--r--app/src/main/res/values/prefs.xml2
-rw-r--r--app/src/main/res/values/strings.xml2
-rw-r--r--app/src/test/java/app/passwordstore/util/viewmodel/StrictDomainRegexTest.kt2
-rw-r--r--autofill-parser/api.txt22
-rw-r--r--autofill-parser/build.gradle.kts5
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillFormParser.kt3
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillHelper.kt49
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillScenario.kt11
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategy.kt3
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategyDsl.kt8
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FeatureAndTrustDetection.kt18
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FormField.kt4
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/PublicSuffixListCache.kt11
-rw-r--r--build-logic/src/main/kotlin/app/passwordstore/gradle/AndroidCommon.kt2
-rwxr-xr-xscripts/boot-emulator.sh6
-rwxr-xr-xscripts/setup-environment.sh6
-rw-r--r--ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Theme.kt3
48 files changed, 87 insertions, 497 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 15d6447e..90375040 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -30,8 +30,7 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppThemeM3"
- tools:ignore="GoogleAppIndexingWarning"
- tools:targetApi="s">
+ tools:ignore="GoogleAppIndexingWarning">
<activity
android:name=".ui.main.LaunchActivity"
diff --git a/app/src/main/java/app/passwordstore/Application.kt b/app/src/main/java/app/passwordstore/Application.kt
index bda61265..60b58cc1 100644
--- a/app/src/main/java/app/passwordstore/Application.kt
+++ b/app/src/main/java/app/passwordstore/Application.kt
@@ -9,7 +9,6 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
-import android.os.Build
import android.os.StrictMode
import androidx.appcompat.app.AppCompatDelegate.*
import app.passwordstore.data.crypto.PGPPassphraseCache
@@ -92,38 +91,24 @@ class Application : android.app.Application(), SharedPreferences.OnSharedPrefere
}
private fun setVmPolicy() {
- val builder =
+ StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectActivityLeaks()
.detectFileUriExposure()
.detectLeakedClosableObjects()
.detectLeakedRegistrationObjects()
.detectLeakedSqlLiteObjects()
-
- builder.detectContentUriWithoutPermission()
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- builder.detectCredentialProtectedWhileLocked().detectImplicitDirectBoot()
- }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- builder.detectNonSdkApiUsage()
- }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- builder.detectIncorrectContextUse().detectUnsafeIntentLaunch()
- }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- builder.penaltyListener(Executors.newSingleThreadExecutor()) { violation ->
- logcat(VERBOSE) { violation.stackTraceToString() }
- }
- } else {
- builder.penaltyLog()
- }
-
- val policy = builder.build()
- StrictMode.setVmPolicy(policy)
+ .detectContentUriWithoutPermission()
+ .detectCredentialProtectedWhileLocked()
+ .detectImplicitDirectBoot()
+ .detectNonSdkApiUsage()
+ .detectIncorrectContextUse()
+ .detectUnsafeIntentLaunch()
+ .penaltyListener(Executors.newSingleThreadExecutor()) { violation ->
+ logcat(VERBOSE) { violation.stackTraceToString() }
+ }
+ .build()
+ )
}
private fun setNightMode() {
diff --git a/app/src/main/java/app/passwordstore/injection/AutofillResponseBuilderModule.kt b/app/src/main/java/app/passwordstore/injection/AutofillResponseBuilderModule.kt
index 46e61397..1717e4cc 100644
--- a/app/src/main/java/app/passwordstore/injection/AutofillResponseBuilderModule.kt
+++ b/app/src/main/java/app/passwordstore/injection/AutofillResponseBuilderModule.kt
@@ -5,8 +5,6 @@
package app.passwordstore.injection
-import android.os.Build
-import app.passwordstore.util.autofill.Api26AutofillResponseBuilder
import app.passwordstore.util.autofill.Api30AutofillResponseBuilder
import app.passwordstore.util.autofill.AutofillResponseBuilder
import dagger.Module
@@ -21,11 +19,6 @@ object AutofillResponseBuilderModule {
@Provides
@Reusable
- fun provideAutofillResponseBuilder(): AutofillResponseBuilder.Factory {
- return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- Api30AutofillResponseBuilder.Factory
- } else {
- Api26AutofillResponseBuilder.Factory
- }
- }
+ fun provideAutofillResponseBuilder(): AutofillResponseBuilder.Factory =
+ Api30AutofillResponseBuilder.Factory
}
diff --git a/app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt b/app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt
index 7ba4df74..6354359f 100644
--- a/app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt
+++ b/app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt
@@ -9,7 +9,6 @@ import android.content.Context
import android.content.Intent
import android.content.IntentSender
import android.content.SharedPreferences
-import android.os.Build
import android.os.Bundle
import android.view.WindowManager
import android.view.autofill.AutofillManager
@@ -368,11 +367,7 @@ class AutofillDecryptActivity : AppCompatActivity() {
context,
decryptFileRequestCode++,
intent,
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE
- } else {
- PendingIntent.FLAG_CANCEL_CURRENT
- },
+ PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE,
)
.intentSender
}
diff --git a/app/src/main/java/app/passwordstore/ui/autofill/AutofillFilterView.kt b/app/src/main/java/app/passwordstore/ui/autofill/AutofillFilterView.kt
index c607b81f..86c2d51d 100644
--- a/app/src/main/java/app/passwordstore/ui/autofill/AutofillFilterView.kt
+++ b/app/src/main/java/app/passwordstore/ui/autofill/AutofillFilterView.kt
@@ -8,7 +8,6 @@ import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.IntentSender
-import android.os.Build
import android.os.Bundle
import android.view.autofill.AutofillManager
import androidx.activity.compose.setContent
@@ -74,11 +73,7 @@ class AutofillFilterView : AppCompatActivity() {
context,
matchAndDecryptFileRequestCode++,
intent,
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE
- } else {
- PendingIntent.FLAG_CANCEL_CURRENT
- },
+ PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE,
)
.intentSender
}
diff --git a/app/src/main/java/app/passwordstore/ui/autofill/AutofillPublisherChangedActivity.kt b/app/src/main/java/app/passwordstore/ui/autofill/AutofillPublisherChangedActivity.kt
index 803896a5..b0dd5dd9 100644
--- a/app/src/main/java/app/passwordstore/ui/autofill/AutofillPublisherChangedActivity.kt
+++ b/app/src/main/java/app/passwordstore/ui/autofill/AutofillPublisherChangedActivity.kt
@@ -9,7 +9,6 @@ import android.content.Context
import android.content.Intent
import android.content.IntentSender
import android.content.pm.PackageManager
-import android.os.Build
import android.os.Bundle
import android.service.autofill.FillResponse
import android.text.format.DateUtils
@@ -54,11 +53,7 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
context,
publisherChangedRequestCode++,
intent,
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE
- } else {
- PendingIntent.FLAG_CANCEL_CURRENT
- },
+ PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE,
)
.intentSender
}
diff --git a/app/src/main/java/app/passwordstore/ui/crypto/CryptoExtensions.kt b/app/src/main/java/app/passwordstore/ui/crypto/CryptoExtensions.kt
index 67343a2e..4a6813f7 100644
--- a/app/src/main/java/app/passwordstore/ui/crypto/CryptoExtensions.kt
+++ b/app/src/main/java/app/passwordstore/ui/crypto/CryptoExtensions.kt
@@ -7,9 +7,7 @@ package app.passwordstore.ui.crypto
import android.content.ClipData
import android.content.Intent
-import android.os.Build
import android.os.PersistableBundle
-import androidx.annotation.StringRes
import androidx.fragment.app.FragmentActivity
import app.passwordstore.R
import app.passwordstore.crypto.PGPIdentifier
@@ -17,7 +15,6 @@ import app.passwordstore.data.repo.PasswordRepository
import app.passwordstore.util.extensions.clipboard
import app.passwordstore.util.extensions.getString
import app.passwordstore.util.extensions.sharedPrefs
-import app.passwordstore.util.extensions.snackbar
import app.passwordstore.util.services.ClipboardService
import app.passwordstore.util.settings.Constants
import app.passwordstore.util.settings.PreferenceKeys
@@ -51,23 +48,13 @@ fun getLongName(fullPath: String, repositoryPath: String, basename: String): Str
}
}
-/**
- * Copies provided [text] to the clipboard, flagged sensitive. Below Android 11 it also shows a
- * snackbar, which can be disabled by passing [showSnackbar] as false.
- */
-fun FragmentActivity.copyTextToClipboard(
- text: String?,
- showSnackbar: Boolean = true,
- @StringRes snackbarTextRes: Int = R.string.clipboard_copied_text,
-) {
+/** Copies provided [text] to the clipboard, flagged sensitive. */
+fun FragmentActivity.copyTextToClipboard(text: String?) {
val clipboard = clipboard ?: return
val clip = ClipData.newPlainText("pgp_handler_result_pm", text)
clip.description.extras =
PersistableBundle().apply { putBoolean("android.content.extra.IS_SENSITIVE", true) }
clipboard.setPrimaryClip(clip)
- if (showSnackbar && Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
- snackbar(message = resources.getString(snackbarTextRes))
- }
}
/**
diff --git a/app/src/main/java/app/passwordstore/ui/editor/EditorViewModel.kt b/app/src/main/java/app/passwordstore/ui/editor/EditorViewModel.kt
index 6d2fbaec..fe5ee772 100644
--- a/app/src/main/java/app/passwordstore/ui/editor/EditorViewModel.kt
+++ b/app/src/main/java/app/passwordstore/ui/editor/EditorViewModel.kt
@@ -10,8 +10,6 @@ import android.content.SharedPreferences
import android.graphics.Bitmap
import android.graphics.ImageDecoder
import android.net.Uri
-import android.os.Build
-import android.provider.MediaStore
import androidx.annotation.StringRes
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -168,12 +166,8 @@ constructor(
return withContext(dispatcherProvider.io()) {
runCatching {
val bitmap =
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- ImageDecoder.decodeBitmap(ImageDecoder.createSource(resolver, uri))
- .copy(Bitmap.Config.ARGB_8888, false)
- } else {
- @Suppress("DEPRECATION") MediaStore.Images.Media.getBitmap(resolver, uri)
- }
+ ImageDecoder.decodeBitmap(ImageDecoder.createSource(resolver, uri))
+ .copy(Bitmap.Config.ARGB_8888, false)
val pixels = IntArray(bitmap.width * bitmap.height)
bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
val source = RGBLuminanceSource(bitmap.width, bitmap.height, pixels)
diff --git a/app/src/main/java/app/passwordstore/ui/settings/ProxyViewModel.kt b/app/src/main/java/app/passwordstore/ui/settings/ProxyViewModel.kt
index fb2bfe93..10f82178 100644
--- a/app/src/main/java/app/passwordstore/ui/settings/ProxyViewModel.kt
+++ b/app/src/main/java/app/passwordstore/ui/settings/ProxyViewModel.kt
@@ -6,7 +6,6 @@
package app.passwordstore.ui.settings
import android.net.InetAddresses
-import android.os.Build
import android.util.Patterns
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -19,10 +18,7 @@ import javax.inject.Inject
/** A numeric address or a plain host name: no scheme, port or path, which the port field holds. */
fun isProxyHost(text: String): Boolean {
- val numeric =
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) InetAddresses.isNumericAddress(text)
- else @Suppress("DEPRECATION") Patterns.IP_ADDRESS.matcher(text).matches()
- return numeric ||
+ return InetAddresses.isNumericAddress(text) ||
(!text.contains(':') && !text.contains('/') && Patterns.DOMAIN_NAME.matcher(text).matches())
}
diff --git a/app/src/main/java/app/passwordstore/util/auth/BiometricAuthenticator.kt b/app/src/main/java/app/passwordstore/util/auth/BiometricAuthenticator.kt
index 98f2229a..8f912879 100644
--- a/app/src/main/java/app/passwordstore/util/auth/BiometricAuthenticator.kt
+++ b/app/src/main/java/app/passwordstore/util/auth/BiometricAuthenticator.kt
@@ -5,7 +5,6 @@
package app.passwordstore.util.auth
import android.app.KeyguardManager
-import android.os.Build
import androidx.annotation.StringRes
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricManager.Authenticators
@@ -23,14 +22,10 @@ object BiometricAuthenticator {
/**
* Keystore keys that require user authentication are unlocked only by the device credential or a
* Class 3 (strong) biometric, so a weak biometric would pass the prompt and then fail to sign or
- * decrypt with `User not authenticated`. Android 9 and 10 do not support combining
- * [Authenticators.BIOMETRIC_STRONG] with [Authenticators.DEVICE_CREDENTIAL], so they keep the
- * weak class.
+ * decrypt with `User not authenticated`.
*/
private val VALID_AUTHENTICATORS =
- Authenticators.DEVICE_CREDENTIAL or
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) Authenticators.BIOMETRIC_STRONG
- else Authenticators.BIOMETRIC_WEAK
+ Authenticators.DEVICE_CREDENTIAL or Authenticators.BIOMETRIC_STRONG
/**
* Sealed class to wrap [BiometricPrompt]'s [Int]-based return codes into more easily-interpreted
diff --git a/app/src/main/java/app/passwordstore/util/autofill/Api26AutofillResponseBuilder.kt b/app/src/main/java/app/passwordstore/util/autofill/Api26AutofillResponseBuilder.kt
deleted file mode 100644
index f38011a7..00000000
--- a/app/src/main/java/app/passwordstore/util/autofill/Api26AutofillResponseBuilder.kt
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-package app.passwordstore.util.autofill
-
-import android.content.Context
-import android.content.IntentSender
-import android.os.Build
-import android.service.autofill.Dataset
-import android.service.autofill.FillCallback
-import android.service.autofill.FillRequest
-import android.service.autofill.FillResponse
-import android.service.autofill.SaveInfo
-import app.passwordstore.ui.autofill.AutofillDecryptActivity
-import app.passwordstore.ui.autofill.AutofillFilterView
-import app.passwordstore.ui.autofill.AutofillPublisherChangedActivity
-import app.passwordstore.ui.autofill.AutofillSaveActivity
-import com.github.androidpasswordstore.autofillparser.AutofillAction
-import com.github.androidpasswordstore.autofillparser.FillableForm
-import com.github.androidpasswordstore.autofillparser.fillWith
-import com.github.michaelbull.result.fold
-import java.io.File
-import logcat.LogPriority.ERROR
-import logcat.asLog
-import logcat.logcat
-
-class Api26AutofillResponseBuilder private constructor(form: FillableForm) :
- AutofillResponseBuilder {
-
- object Factory : AutofillResponseBuilder.Factory {
- override fun create(form: FillableForm): AutofillResponseBuilder =
- Api26AutofillResponseBuilder(form)
- }
-
- private val formOrigin = form.formOrigin
- private val scenario = form.scenario
- private val ignoredIds = form.ignoredIds
- private val saveFlags = form.saveFlags
- private val clientState = form.toClientState()
-
- // We do not offer save when the only relevant field is a username field or there is no field.
- private val scenarioSupportsSave = scenario.hasPasswordFieldsToSave
- private val canBeSaved = saveFlags != null && scenarioSupportsSave
-
- @Suppress("DEPRECATION")
- private fun makeIntentDataset(
- context: Context,
- action: AutofillAction,
- intentSender: IntentSender,
- metadata: DatasetMetadata,
- ): Dataset {
- return Dataset.Builder(makeRemoteView(context, metadata)).run {
- fillWith(scenario, action, credentials = null)
- setAuthentication(intentSender)
- build()
- }
- }
-
- private fun makeMatchDataset(context: Context, file: File): Dataset? {
- if (!scenario.hasFieldsToFillOn(AutofillAction.Match)) return null
- val metadata = makeFillMatchMetadata(context, file)
- val intentSender = AutofillDecryptActivity.makeDecryptFileIntentSender(file, context)
- return makeIntentDataset(context, AutofillAction.Match, intentSender, metadata)
- }
-
- private fun makeSearchDataset(context: Context): Dataset? {
- if (!scenario.hasFieldsToFillOn(AutofillAction.Search)) return null
- val metadata = makeSearchAndFillMetadata(context)
- val intentSender = AutofillFilterView.makeMatchAndDecryptFileIntentSender(context, formOrigin)
- return makeIntentDataset(context, AutofillAction.Search, intentSender, metadata)
- }
-
- private fun makeGenerateDataset(context: Context): Dataset? {
- if (!scenario.hasFieldsToFillOn(AutofillAction.Generate)) return null
- val metadata = makeGenerateAndFillMetadata(context)
- val intentSender = AutofillSaveActivity.makeSaveIntentSender(context, null, formOrigin)
- return makeIntentDataset(context, AutofillAction.Generate, intentSender, metadata)
- }
-
- private fun makePublisherChangedDataset(
- context: Context,
- publisherChangedException: AutofillPublisherChangedException,
- ): Dataset {
- val metadata = makeWarningMetadata(context)
- // If the user decides to trust the new publisher, they can choose reset the list of
- // matches. In this case we need to immediately show a new `FillResponse` as if the app were
- // autofilled for the first time. This `FillResponse` needs to be returned as a result from
- // `AutofillPublisherChangedActivity`, which is why we create and pass it on here.
- val fillResponseAfterReset = makeFillResponse(context, emptyList())
- val intentSender =
- AutofillPublisherChangedActivity.makePublisherChangedIntentSender(
- context,
- publisherChangedException,
- fillResponseAfterReset,
- )
- return makeIntentDataset(context, AutofillAction.Match, intentSender, metadata)
- }
-
- private fun makePublisherChangedResponse(
- context: Context,
- publisherChangedException: AutofillPublisherChangedException,
- ): FillResponse {
- return FillResponse.Builder().run {
- addDataset(makePublisherChangedDataset(context, publisherChangedException))
- setIgnoredIds(*ignoredIds.toTypedArray())
- build()
- }
- }
-
- // TODO: Support multi-step authentication flows in apps via FLAG_DELAY_SAVE
- // See:
- // https://developer.android.com/reference/android/service/autofill/SaveInfo#FLAG_DELAY_SAVE
- private fun makeSaveInfo(): SaveInfo? {
- if (!canBeSaved) return null
- check(saveFlags != null) { "saveFlags must not be null" }
- val idsToSave = scenario.fieldsToSave.toTypedArray()
- if (idsToSave.isEmpty()) return null
- var saveDataTypes = SaveInfo.SAVE_DATA_TYPE_PASSWORD
- if (scenario.hasUsername) {
- saveDataTypes = saveDataTypes or SaveInfo.SAVE_DATA_TYPE_USERNAME
- }
- return SaveInfo.Builder(saveDataTypes, idsToSave).run {
- setFlags(saveFlags)
- build()
- }
- }
-
- private fun makeFillResponse(context: Context, matchedFiles: List<File>): FillResponse? {
- var datasetCount = 0
- return FillResponse.Builder().run {
- for (file in matchedFiles) {
- makeMatchDataset(context, file)?.let {
- datasetCount++
- addDataset(it)
- }
- }
- makeGenerateDataset(context)?.let {
- datasetCount++
- addDataset(it)
- }
- makeSearchDataset(context)?.let {
- datasetCount++
- addDataset(it)
- }
- if (datasetCount == 0) return null
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- setHeader(
- makeRemoteView(
- context,
- makeHeaderMetadata(formOrigin.getPrettyIdentifier(context, untrusted = true)),
- )
- )
- }
- makeSaveInfo()?.let { setSaveInfo(it) }
- setClientState(clientState)
- setIgnoredIds(*ignoredIds.toTypedArray())
- build()
- }
- }
-
- /** Creates and returns a suitable [FillResponse] to the Autofill framework. */
- override fun fillCredentials(context: Context, fillRequest: FillRequest, callback: FillCallback) {
- AutofillMatcher.getMatchesFor(context, formOrigin)
- .fold(
- success = { matchedFiles -> callback.onSuccess(makeFillResponse(context, matchedFiles)) },
- failure = { e ->
- logcat(ERROR) { e.asLog() }
- callback.onSuccess(makePublisherChangedResponse(context, e))
- },
- )
- }
-}
diff --git a/app/src/main/java/app/passwordstore/util/autofill/Api30AutofillResponseBuilder.kt b/app/src/main/java/app/passwordstore/util/autofill/Api30AutofillResponseBuilder.kt
index 55679b21..bf41327f 100644
--- a/app/src/main/java/app/passwordstore/util/autofill/Api30AutofillResponseBuilder.kt
+++ b/app/src/main/java/app/passwordstore/util/autofill/Api30AutofillResponseBuilder.kt
@@ -31,7 +31,6 @@ import logcat.asLog
import logcat.logcat
/** Implements [AutofillResponseBuilder]'s methods for API 30 and above */
-@RequiresApi(Build.VERSION_CODES.R)
class Api30AutofillResponseBuilder private constructor(form: FillableForm) :
AutofillResponseBuilder {
diff --git a/app/src/main/java/app/passwordstore/util/autofill/AutofillResponseBuilder.kt b/app/src/main/java/app/passwordstore/util/autofill/AutofillResponseBuilder.kt
index bfa47d74..a98aefc5 100644
--- a/app/src/main/java/app/passwordstore/util/autofill/AutofillResponseBuilder.kt
+++ b/app/src/main/java/app/passwordstore/util/autofill/AutofillResponseBuilder.kt
@@ -6,7 +6,6 @@
package app.passwordstore.util.autofill
import android.content.Context
-import android.os.Build
import android.os.Bundle
import android.service.autofill.Dataset
import android.service.autofill.FillCallback
@@ -34,19 +33,11 @@ interface AutofillResponseBuilder {
action: AutofillAction,
): Dataset {
val scenario = AutofillScenario.fromClientState(clientState)
- // Before Android P, Datasets used for fill-in had to come with a RemoteViews, even
- // though they are rarely shown.
// FIXME: We should clone the original dataset here and add the credentials to be filled
// in. Otherwise, the entry in the cached list of datasets will be overwritten by the
// fill-in dataset without any visual representation. This causes it to be missing from
// the Autofill suggestions shown after the user clears the filled out form fields.
- val builder =
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- Dataset.Builder()
- } else {
- @Suppress("DEPRECATION") Dataset.Builder(makeRemoteView(context, makeEmptyMetadata()))
- }
- return builder.run {
+ return Dataset.Builder().run {
if (scenario != null) fillWith(scenario, action, credentials)
else logcat(LogPriority.ERROR) { "Failed to recover scenario from client state" }
build()
diff --git a/app/src/main/java/app/passwordstore/util/autofill/AutofillViewUtils.kt b/app/src/main/java/app/passwordstore/util/autofill/AutofillViewUtils.kt
index 59fd5cca..321c111a 100644
--- a/app/src/main/java/app/passwordstore/util/autofill/AutofillViewUtils.kt
+++ b/app/src/main/java/app/passwordstore/util/autofill/AutofillViewUtils.kt
@@ -10,7 +10,6 @@ import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.graphics.drawable.Icon
-import android.os.Build
import android.service.autofill.InlinePresentation
import android.view.View
import android.widget.RemoteViews
@@ -47,8 +46,6 @@ fun makeInlinePresentation(
imeSpec: InlinePresentationSpec,
metadata: DatasetMetadata,
): InlinePresentation? {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return null
-
if (UiVersions.INLINE_UI_VERSION_1 !in UiVersions.getVersions(imeSpec.style)) return null
val launchIntent =
@@ -56,11 +53,7 @@ fun makeInlinePresentation(
context,
0,
Intent(context, LaunchActivity::class.java),
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- PendingIntent.FLAG_MUTABLE
- } else {
- 0
- },
+ PendingIntent.FLAG_MUTABLE,
)
val slice =
InlineSuggestionUi.newContentBuilder(launchIntent).run {
@@ -101,8 +94,6 @@ fun makeGenerateAndFillMetadata(context: Context) =
R.drawable.ic_autofill_new_password,
)
-fun makeEmptyMetadata() = DatasetMetadata("PLACEHOLDER", "PLACEHOLDER", R.mipmap.ic_launcher)
-
fun makeWarningMetadata(context: Context) =
DatasetMetadata(
context.getString(R.string.oreo_autofill_warning_publisher_dataset_title),
diff --git a/app/src/main/java/app/passwordstore/util/crypto/KeystorePreferences.kt b/app/src/main/java/app/passwordstore/util/crypto/KeystorePreferences.kt
index f4d43e95..e23ec896 100644
--- a/app/src/main/java/app/passwordstore/util/crypto/KeystorePreferences.kt
+++ b/app/src/main/java/app/passwordstore/util/crypto/KeystorePreferences.kt
@@ -7,7 +7,6 @@ package app.passwordstore.util.crypto
import android.content.Context
import android.content.SharedPreferences
-import android.os.Build
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.security.keystore.StrongBoxUnavailableException
@@ -66,18 +65,14 @@ fun keystoreAesKey(
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.apply(configure)
- .apply {
- if (useStrongBox && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- setIsStrongBoxBacked(true)
- }
- }
+ .setIsStrongBoxBacked(useStrongBox)
.build()
return KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore").run {
init(spec)
generateKey()
}
}
- if (!strongBox || Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return generate(false)
+ if (!strongBox) return generate(false)
return try {
generate(true)
} catch (_: StrongBoxUnavailableException) {
@@ -91,14 +86,10 @@ fun keystoreAesKey(
*/
fun KeyGenParameterSpec.Builder.requireUserAuthentication(seconds: Int) {
setUserAuthenticationRequired(true)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- setUserAuthenticationParameters(
- seconds,
- KeyProperties.AUTH_DEVICE_CREDENTIAL or KeyProperties.AUTH_BIOMETRIC_STRONG,
- )
- } else {
- @Suppress("DEPRECATION") setUserAuthenticationValidityDurationSeconds(seconds)
- }
+ setUserAuthenticationParameters(
+ seconds,
+ KeyProperties.AUTH_DEVICE_CREDENTIAL or KeyProperties.AUTH_BIOMETRIC_STRONG,
+ )
}
/**
diff --git a/app/src/main/java/app/passwordstore/util/extensions/AndroidExtensions.kt b/app/src/main/java/app/passwordstore/util/extensions/AndroidExtensions.kt
index 6528334d..9bc93d8e 100644
--- a/app/src/main/java/app/passwordstore/util/extensions/AndroidExtensions.kt
+++ b/app/src/main/java/app/passwordstore/util/extensions/AndroidExtensions.kt
@@ -30,7 +30,7 @@ import com.github.michaelbull.result.Result
import com.google.android.material.snackbar.Snackbar
import logcat.logcat
-/** Get an instance of [AutofillManager]. Only available on Android Oreo and above */
+/** Get an instance of [AutofillManager] */
val Context.autofillManager: AutofillManager?
get() = getSystemService()
diff --git a/app/src/main/java/app/passwordstore/util/git/sshj/SshKey.kt b/app/src/main/java/app/passwordstore/util/git/sshj/SshKey.kt
index 7c8f5ba5..e2a2c2dd 100644
--- a/app/src/main/java/app/passwordstore/util/git/sshj/SshKey.kt
+++ b/app/src/main/java/app/passwordstore/util/git/sshj/SshKey.kt
@@ -7,7 +7,6 @@ package app.passwordstore.util.git.sshj
import android.content.Context
import android.content.pm.PackageManager
import android.net.Uri
-import android.os.Build
import android.provider.OpenableColumns
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyInfo
@@ -157,9 +156,7 @@ object SshKey {
context.sharedPrefs.edit { putString(PreferenceKeys.GIT_REMOTE_KEY_TYPE, value?.value) }
private val isStrongBoxSupported by unsafeLazy {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
- context.packageManager.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)
- else false
+ context.packageManager.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)
}
private enum class Type(val value: String) {
@@ -198,9 +195,7 @@ object SshKey {
setKeySize(256)
setAlgorithmParameterSpec(java.security.spec.ECGenParameterSpec("secp256r1"))
setDigests(KeyProperties.DIGEST_SHA256)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- setIsStrongBoxBacked(isStrongBoxSupported)
- }
+ setIsStrongBoxBacked(isStrongBoxSupported)
},
),
}
@@ -316,17 +311,7 @@ object SshKey {
val parameterSpec =
KeyGenParameterSpec.Builder(KEYSTORE_ALIAS, KeyProperties.PURPOSE_SIGN).run {
apply(algorithm.applyToSpec)
- if (requireAuthentication) {
- setUserAuthenticationRequired(true)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- setUserAuthenticationParameters(
- 30,
- KeyProperties.AUTH_DEVICE_CREDENTIAL or KeyProperties.AUTH_BIOMETRIC_STRONG,
- )
- } else {
- @Suppress("DEPRECATION") setUserAuthenticationValidityDurationSeconds(30)
- }
- }
+ if (requireAuthentication) requireUserAuthentication(30)
build()
}
val keyPair =
diff --git a/app/src/main/java/app/passwordstore/util/services/ClipboardService.kt b/app/src/main/java/app/passwordstore/util/services/ClipboardService.kt
index b4bb0438..3347da78 100644
--- a/app/src/main/java/app/passwordstore/util/services/ClipboardService.kt
+++ b/app/src/main/java/app/passwordstore/util/services/ClipboardService.kt
@@ -12,7 +12,6 @@ import android.app.PendingIntent
import android.app.Service
import android.content.ClipData
import android.content.Intent
-import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.content.getSystemService
@@ -121,11 +120,7 @@ class ClipboardService : Service() {
this,
0,
clearIntent,
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
- } else {
- PendingIntent.FLAG_UPDATE_CURRENT
- },
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE,
)
val notification = createNotification(pendingIntent, clearTimeMs)
diff --git a/app/src/main/java/app/passwordstore/util/services/OreoAutofillService.kt b/app/src/main/java/app/passwordstore/util/services/OreoAutofillService.kt
index beeb4be7..a8b525d5 100644
--- a/app/src/main/java/app/passwordstore/util/services/OreoAutofillService.kt
+++ b/app/src/main/java/app/passwordstore/util/services/OreoAutofillService.kt
@@ -5,7 +5,6 @@
package app.passwordstore.util.services
import android.content.Context
-import android.os.Build
import android.os.CancellationSignal
import android.service.autofill.AutofillService
import android.service.autofill.FillCallback
@@ -74,16 +73,12 @@ class OreoAutofillService : AutofillService() {
return
}
if (structure.activityComponent.packageName in DENYLISTED_PACKAGES) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- callback.onSuccess(
- FillResponse.Builder().run {
- disableAutofill(DISABLE_AUTOFILL_DURATION_MS)
- build()
- }
- )
- } else {
- callback.onSuccess(null)
- }
+ callback.onSuccess(
+ FillResponse.Builder().run {
+ disableAutofill(DISABLE_AUTOFILL_DURATION_MS)
+ build()
+ }
+ )
return
}
val formToFill =
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index a0a20dc7..7baf4113 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -37,7 +37,6 @@
<string name="git_commit_move_multiple_text">Verschiebe mehrere Passwörter nach %1$s.</string>
<string name="git_commit_gpg_id">Initialisiere PGP-IDs in %1$s.</string>
<!-- PGPHandler -->
- <string name="clipboard_copied_text">In die Zwischenablage kopiert</string>
<string name="file_toast_text">Bitte setzen Sie einen Dateinamen.</string>
<string name="empty_toast_text">Sie können kein leeres Passwort oder leere Extra-Angaben setzen.</string>
<!-- Git Async Task -->
@@ -232,7 +231,6 @@
<string name="pref_app_theme_title">App-Farbthema</string>
<string name="pref_app_theme_value_light">Hell</string>
<string name="pref_app_theme_value_dark">Dunkel</string>
- <string name="pref_app_theme_value_battery_saver">Durch Energiesparmodus gesetzt</string>
<string name="pref_app_theme_value_follow_system">Systemstandard</string>
<string name="connection_mode_ssh_key">SSH-Schlüssel</string>
<string name="connection_mode_basic_authentication">Passwort</string>
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index d4d4d424..57be2b30 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -36,7 +36,6 @@
<string name="git_commit_move_text">Renommer %1$sà %2$s. </string>
<string name="git_commit_move_multiple_text">Déplacement de mots de passe vers %1$s.</string>
<!-- PGPHandler -->
- <string name="clipboard_copied_text">Copié dans le presse-papiers</string>
<string name="file_toast_text">Veuillez fournir un nom de fichier</string>
<string name="empty_toast_text">Vous ne pouvez pas utiliser un mot de passe vide ou des données supplémentaires vide</string>
<!-- Git Async Task -->
@@ -220,7 +219,6 @@
<string name="pref_app_theme_title">Thème de l\'application</string>
<string name="pref_app_theme_value_light">Clair</string>
<string name="pref_app_theme_value_dark">Sombre</string>
- <string name="pref_app_theme_value_battery_saver">Défini par l\'économiseur de batterie</string>
<string name="pref_app_theme_value_follow_system">Valeur par défaut du système</string>
<string name="connection_mode_ssh_key">Clé SSH</string>
<string name="connection_mode_basic_authentication">Mot de passe</string>
diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml
index f966230c..b7a59428 100644
--- a/app/src/main/res/values-gl/strings.xml
+++ b/app/src/main/res/values-gl/strings.xml
@@ -37,7 +37,6 @@
<string name="git_commit_move_multiple_text">Mover varios contrasinais a %1$s.</string>
<string name="git_commit_gpg_id">Iniciar cos IDs GPG en %1$s.</string>
<!-- PGPHandler -->
- <string name="clipboard_copied_text">Copiado ao portapapeis</string>
<string name="file_toast_text">Debes proporcionar un nome de ficheiro</string>
<string name="empty_toast_text">Non podes deixar baleiro o contrasinal ou o contido extra</string>
<!-- Git Async Task -->
@@ -234,7 +233,6 @@ a app desde unha fonte de confianza, como a Play Store, Amazon Appstore, F-Droid
<string name="pref_app_theme_title">Decorado da App</string>
<string name="pref_app_theme_value_light">Claro</string>
<string name="pref_app_theme_value_dark">Escuro</string>
- <string name="pref_app_theme_value_battery_saver">Establecido polo Aforrador de enerxía</string>
<string name="pref_app_theme_value_follow_system">Por omisión do sistema</string>
<string name="connection_mode_ssh_key">Chave SSH</string>
<string name="connection_mode_basic_authentication">Contrasinal</string>
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index e7c05909..e15b903f 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -36,7 +36,6 @@
<string name="git_commit_move_text">Rinomina %1$s in %2$s.</string>
<string name="git_commit_move_multiple_text">Sposta più password in %1$s.</string>
<!-- PGPHandler -->
- <string name="clipboard_copied_text">Copiato negli appunti</string>
<string name="file_toast_text">Inserisci un nome per il file</string>
<string name="empty_toast_text">Non puoi usare una password vuota o dei contenuti extra vuoti</string>
<!-- Git Async Task -->
@@ -215,7 +214,6 @@
<string name="pref_app_theme_title">Tema dell\'App</string>
<string name="pref_app_theme_value_light">Chiaro</string>
<string name="pref_app_theme_value_dark">Scuro</string>
- <string name="pref_app_theme_value_battery_saver">Impostato dal Risparmio Energetico</string>
<string name="pref_app_theme_value_follow_system">Predefinito del sistema</string>
<string name="connection_mode_ssh_key">Chiave SSH</string>
<string name="connection_mode_basic_authentication">Password</string>
diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/app/src/main/res/values-ko-rKR/strings.xml
index add3de87..f6535e05 100644
--- a/app/src/main/res/values-ko-rKR/strings.xml
+++ b/app/src/main/res/values-ko-rKR/strings.xml
@@ -35,7 +35,6 @@
<string name="git_commit_move_multiple_text">여러개의 비밀번호를 %1$s 로 옮겼습니다.</string>
<string name="git_commit_gpg_id">%1$s의 GPG ID를 초기화 합니다.</string>
<!-- PGPHandler -->
- <string name="clipboard_copied_text">클립보드로 복사됨</string>
<string name="file_toast_text">파일 이름이 필요합니다</string>
<string name="empty_toast_text">비어있는 비밀번호나 추가 정보를 사용할 수 없습니다</string>
<!-- Git Async Task -->
@@ -228,7 +227,6 @@
<string name="pref_app_theme_title">앱 테마</string>
<string name="pref_app_theme_value_light">밝은 테마</string>
<string name="pref_app_theme_value_dark">어두운 테마</string>
- <string name="pref_app_theme_value_battery_saver">배터리 절약모드 설정</string>
<string name="pref_app_theme_value_follow_system">시스템 기본값</string>
<string name="connection_mode_ssh_key">SSH 키</string>
<string name="connection_mode_basic_authentication">비밀번호</string>
diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml
index 4d41b2f6..d130bc70 100644
--- a/app/src/main/res/values-pl-rPL/strings.xml
+++ b/app/src/main/res/values-pl-rPL/strings.xml
@@ -35,7 +35,6 @@
<string name="git_commit_move_text">Zmień nazwę %1$s na %2$s.</string>
<string name="git_commit_move_multiple_text">Przenieś hasła do %1$s.</string>
<!-- PGPHandler -->
- <string name="clipboard_copied_text">Skopiowano do schowka</string>
<string name="file_toast_text">Podaj nazwę pliku</string>
<string name="empty_toast_text">Nie możesz użyć pustego hasła lub pustej dodatkowej zawartości</string>
<!-- Git Async Task -->
@@ -227,7 +226,6 @@
<string name="pref_app_theme_title">Motyw aplikacji</string>
<string name="pref_app_theme_value_light">Jasny</string>
<string name="pref_app_theme_value_dark">Ciemny</string>
- <string name="pref_app_theme_value_battery_saver">Ustawiany przez funkcję oszczędzania energii</string>
<string name="pref_app_theme_value_follow_system">Domyślny</string>
<string name="connection_mode_ssh_key">Klucz SSH</string>
<string name="connection_mode_basic_authentication">Hasło</string>
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index 14e862c5..4ee08b50 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -37,7 +37,6 @@
<string name="git_commit_move_multiple_text">Mova múltiplas senhas para %1$s.</string>
<string name="git_commit_gpg_id">Inicializar IDs GPG em %1$s.</string>
<!-- PGPHandler -->
- <string name="clipboard_copied_text">Copiado para a área de transferência</string>
<string name="file_toast_text">Por favor, informe um nome de arquivo</string>
<string name="empty_toast_text">Você não pode usar uma senha vazia ou conteúdo extra vazio</string>
<!-- Git Async Task -->
@@ -232,7 +231,6 @@
<string name="pref_app_theme_title">Tema do aplicativo</string>
<string name="pref_app_theme_value_light">Claro</string>
<string name="pref_app_theme_value_dark">Escuro</string>
- <string name="pref_app_theme_value_battery_saver">Configurado pela Economia de bateria</string>
<string name="pref_app_theme_value_follow_system">Padrão do sistema</string>
<string name="connection_mode_ssh_key">Chave SSH</string>
<string name="connection_mode_basic_authentication">Senha</string>
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index ddc33aa3..a966640d 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -41,7 +41,6 @@
<string name="git_commit_move_multiple_text">Переместить несколько паролей в %1$s.</string>
<string name="git_commit_gpg_id">Инициализация GPG ID через %1$s.</string>
<!-- PGPHandler -->
- <string name="clipboard_copied_text">Скопировано в буфер обмена</string>
<string name="file_toast_text">Пожалуйста, укажите имя файла</string>
<string name="empty_toast_text">Вы не можете использовать пустой пароль или пустое поле информации</string>
<!-- Git Async Task -->
@@ -225,7 +224,6 @@
<string name="pref_app_theme_title">Тема приложения</string>
<string name="pref_app_theme_value_light">Светлая</string>
<string name="pref_app_theme_value_dark">Темная</string>
- <string name="pref_app_theme_value_battery_saver">Задается экономией батареи</string>
<string name="pref_app_theme_value_follow_system">Системная</string>
<string name="connection_mode_ssh_key">SSH ключ</string>
<string name="connection_mode_basic_authentication">Пароль</string>
diff --git a/app/src/main/res/values-v29/arrays.xml b/app/src/main/res/values-v29/arrays.xml
deleted file mode 100644
index aa78032c..00000000
--- a/app/src/main/res/values-v29/arrays.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved.
- ~ SPDX-License-Identifier: GPL-3.0-only
- -->
-
-<resources>
- <string-array name="app_theme_options">
- <item>@string/pref_app_theme_value_light</item>
- <item>@string/pref_app_theme_value_dark</item>
- <item>@string/pref_app_theme_value_follow_system</item>
- </string-array>
- <string-array name="app_theme_values">
- <item>light</item>
- <item>dark</item>
- <item>follow_system</item>
- </string-array>
-</resources>
diff --git a/app/src/main/res/values-v29/prefs.xml b/app/src/main/res/values-v29/prefs.xml
deleted file mode 100644
index 383b5f8b..00000000
--- a/app/src/main/res/values-v29/prefs.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved.
- ~ SPDX-License-Identifier: GPL-3.0-only
- -->
-
-<resources>
- <string name="app_theme_def" translatable="false">follow_system</string>
-</resources>
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index 3f6abeb3..dae54d05 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -36,7 +36,6 @@
<string name="git_commit_move_multiple_text">将多个密码移至%1$s</string>
<string name="git_commit_gpg_id">初始化 %1$s 中的 GPG ID</string>
<!-- PGPHandler -->
- <string name="clipboard_copied_text">复制到剪切板</string>
<string name="file_toast_text">请提供文件名</string>
<string name="empty_toast_text">您不能使用空密码或空额外内容</string>
<!-- Git Async Task -->
@@ -233,7 +232,6 @@
<string name="pref_app_theme_title">应用主题</string>
<string name="pref_app_theme_value_light">浅色</string>
<string name="pref_app_theme_value_dark">深色</string>
- <string name="pref_app_theme_value_battery_saver">由省电模式设定</string>
<string name="pref_app_theme_value_follow_system">系统默认</string>
<string name="connection_mode_ssh_key">SSH密钥</string>
<string name="connection_mode_basic_authentication">密码</string>
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 2891987d..dde1a99f 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -33,12 +33,12 @@
<string-array name="app_theme_options">
<item>@string/pref_app_theme_value_light</item>
<item>@string/pref_app_theme_value_dark</item>
- <item>@string/pref_app_theme_value_battery_saver</item>
+ <item>@string/pref_app_theme_value_follow_system</item>
</string-array>
<string-array name="app_theme_values">
<item>light</item>
<item>dark</item>
- <item>battery_saver</item>
+ <item>follow_system</item>
</string-array>
</resources>
diff --git a/app/src/main/res/values/prefs.xml b/app/src/main/res/values/prefs.xml
index a5977d9d..383b5f8b 100644
--- a/app/src/main/res/values/prefs.xml
+++ b/app/src/main/res/values/prefs.xml
@@ -4,5 +4,5 @@
-->
<resources>
- <string name="app_theme_def" translatable="false">battery_saver</string>
+ <string name="app_theme_def" translatable="false">follow_system</string>
</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f1a858fd..755fa9bc 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -44,7 +44,6 @@
<string name="git_commit_gpg_id">Initialize GPG IDs in %1$s.</string>
<!-- PGPHandler -->
- <string name="clipboard_copied_text">Copied to clipboard</string>
<string name="file_toast_text">Please provide a file name</string>
<string name="empty_toast_text">You cannot use an empty password or empty extra content</string>
@@ -263,7 +262,6 @@
<string name="pref_app_theme_title">App theme</string>
<string name="pref_app_theme_value_light">Light</string>
<string name="pref_app_theme_value_dark">Dark</string>
- <string name="pref_app_theme_value_battery_saver">Set by Battery Saver</string>
<string name="pref_app_theme_value_follow_system">System default</string>
<string name="connection_mode_ssh_key">SSH key</string>
<string name="connection_mode_basic_authentication">Password</string>
diff --git a/app/src/test/java/app/passwordstore/util/viewmodel/StrictDomainRegexTest.kt b/app/src/test/java/app/passwordstore/util/viewmodel/StrictDomainRegexTest.kt
index 0ddb72f8..59c1de05 100644
--- a/app/src/test/java/app/passwordstore/util/viewmodel/StrictDomainRegexTest.kt
+++ b/app/src/test/java/app/passwordstore/util/viewmodel/StrictDomainRegexTest.kt
@@ -10,13 +10,11 @@ import kotlin.test.assertNull
import kotlin.test.assertTrue
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
-import org.robolectric.annotation.Config
private infix fun String.matchedForDomain(domain: String) =
SearchableRepositoryViewModel.generateStrictDomainRegex(domain)?.containsMatchIn(this) == true
@RunWith(RobolectricTestRunner::class)
-@Config(sdk = [23])
class StrictDomainRegexTest {
@Test
diff --git a/autofill-parser/api.txt b/autofill-parser/api.txt
index 89cfaa3c..09b2974f 100644
--- a/autofill-parser/api.txt
+++ b/autofill-parser/api.txt
@@ -12,7 +12,7 @@ package com.github.androidpasswordstore.autofillparser {
method public static String computeCertificatesHash(android.content.Context context, String appPackage);
}
- @RequiresApi(android.os.Build.VERSION_CODES.O) public abstract sealed nonexhaustive class AutofillScenario<T> {
+ public abstract sealed nonexhaustive class AutofillScenario<T> {
method @InaccessibleFromKotlin public final java.util.List<T> getFieldsToSave();
method @InaccessibleFromKotlin public final boolean getHasFieldsToSave();
method @InaccessibleFromKotlin public final boolean getHasPasswordFieldsToSave();
@@ -35,13 +35,13 @@ package com.github.androidpasswordstore.autofillparser {
}
public final class AutofillScenarioKt {
- method @KotlinOnly @RequiresApi(android.os.Build.VERSION_CODES.O) public static void fillWith(android.service.autofill.Dataset.Builder, com.github.androidpasswordstore.autofillparser.AutofillScenario<android.view.autofill.AutofillId> scenario, com.github.androidpasswordstore.autofillparser.AutofillAction action, com.github.androidpasswordstore.autofillparser.Credentials? credentials);
- method @InaccessibleFromKotlin @RequiresApi(android.os.Build.VERSION_CODES.O) public static void fillWithAutofillId(android.service.autofill.Dataset.Builder, com.github.androidpasswordstore.autofillparser.AutofillScenario<android.view.autofill.AutofillId> scenario, com.github.androidpasswordstore.autofillparser.AutofillAction action, com.github.androidpasswordstore.autofillparser.Credentials? credentials);
- method @InaccessibleFromKotlin @RequiresApi(android.os.Build.VERSION_CODES.O) public static String? getPasswordValue(com.github.androidpasswordstore.autofillparser.AutofillScenario<? extends android.app.assist.AssistStructure.ViewNode>);
- method @InaccessibleFromKotlin @RequiresApi(android.os.Build.VERSION_CODES.O) public static String? getUsernameValue(com.github.androidpasswordstore.autofillparser.AutofillScenario<? extends android.app.assist.AssistStructure.ViewNode>);
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public static com.github.androidpasswordstore.autofillparser.AutofillScenario<android.app.assist.AssistStructure.ViewNode>? recoverNodes(com.github.androidpasswordstore.autofillparser.AutofillScenario<android.view.autofill.AutofillId>, android.app.assist.AssistStructure structure);
- property @RequiresApi(android.os.Build.VERSION_CODES.O) public static String? com.github.androidpasswordstore.autofillparser.AutofillScenario<android.app.assist.AssistStructure.ViewNode>.passwordValue;
- property @RequiresApi(android.os.Build.VERSION_CODES.O) public static String? com.github.androidpasswordstore.autofillparser.AutofillScenario<android.app.assist.AssistStructure.ViewNode>.usernameValue;
+ method @KotlinOnly public static void fillWith(android.service.autofill.Dataset.Builder, com.github.androidpasswordstore.autofillparser.AutofillScenario<android.view.autofill.AutofillId> scenario, com.github.androidpasswordstore.autofillparser.AutofillAction action, com.github.androidpasswordstore.autofillparser.Credentials? credentials);
+ method @InaccessibleFromKotlin public static void fillWithAutofillId(android.service.autofill.Dataset.Builder, com.github.androidpasswordstore.autofillparser.AutofillScenario<android.view.autofill.AutofillId> scenario, com.github.androidpasswordstore.autofillparser.AutofillAction action, com.github.androidpasswordstore.autofillparser.Credentials? credentials);
+ method @InaccessibleFromKotlin public static String? getPasswordValue(com.github.androidpasswordstore.autofillparser.AutofillScenario<? extends android.app.assist.AssistStructure.ViewNode>);
+ method @InaccessibleFromKotlin public static String? getUsernameValue(com.github.androidpasswordstore.autofillparser.AutofillScenario<? extends android.app.assist.AssistStructure.ViewNode>);
+ method public static com.github.androidpasswordstore.autofillparser.AutofillScenario<android.app.assist.AssistStructure.ViewNode>? recoverNodes(com.github.androidpasswordstore.autofillparser.AutofillScenario<android.view.autofill.AutofillId>, android.app.assist.AssistStructure structure);
+ property public static String? com.github.androidpasswordstore.autofillparser.AutofillScenario<android.app.assist.AssistStructure.ViewNode>.passwordValue;
+ property public static String? com.github.androidpasswordstore.autofillparser.AutofillScenario<android.app.assist.AssistStructure.ViewNode>.usernameValue;
}
public enum BrowserAutofillSupportLevel {
@@ -68,10 +68,10 @@ package com.github.androidpasswordstore.autofillparser {
}
public final class FeatureAndTrustDetectionKt {
- method @RequiresApi(android.os.Build.VERSION_CODES.O) public static java.util.List<kotlin.Pair<java.lang.String,com.github.androidpasswordstore.autofillparser.BrowserAutofillSupportLevel>> getInstalledBrowsersWithAutofillSupportLevel(android.content.Context context);
+ method public static java.util.List<kotlin.Pair<java.lang.String,com.github.androidpasswordstore.autofillparser.BrowserAutofillSupportLevel>> getInstalledBrowsersWithAutofillSupportLevel(android.content.Context context);
}
- @RequiresApi(android.os.Build.VERSION_CODES.O) public final class FillableForm {
+ public final class FillableForm {
method @InaccessibleFromKotlin public com.github.androidpasswordstore.autofillparser.FormOrigin getFormOrigin();
method @InaccessibleFromKotlin public java.util.List<android.view.autofill.AutofillId> getIgnoredIds();
method @InaccessibleFromKotlin public Integer? getSaveFlags();
@@ -88,7 +88,7 @@ package com.github.androidpasswordstore.autofillparser {
method public com.github.androidpasswordstore.autofillparser.FillableForm? parseAssistStructure(android.content.Context context, android.app.assist.AssistStructure structure, boolean isManualRequest, optional kotlin.sequences.Sequence<java.lang.String> customSuffixes);
}
- @RequiresApi(android.os.Build.VERSION_CODES.O) public final class FixedSaveCallback {
+ public final class FixedSaveCallback {
ctor public FixedSaveCallback(android.content.Context context, android.service.autofill.SaveCallback callback);
method public void onFailure(CharSequence message);
method public void onSuccess(android.content.IntentSender intentSender);
diff --git a/autofill-parser/build.gradle.kts b/autofill-parser/build.gradle.kts
index 39157b37..30a952b9 100644
--- a/autofill-parser/build.gradle.kts
+++ b/autofill-parser/build.gradle.kts
@@ -11,10 +11,7 @@ plugins {
}
android {
- defaultConfig {
- minSdk = 23
- consumerProguardFiles("consumer-rules.pro")
- }
+ defaultConfig { consumerProguardFiles("consumer-rules.pro") }
sourceSets { getByName("test") { resources.directories.add("src/main/assets") } }
namespace = "com.github.androidpasswordstore.autofillparser"
}
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillFormParser.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillFormParser.kt
index 3dc74f33..eba3b2bc 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillFormParser.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillFormParser.kt
@@ -11,7 +11,6 @@ import android.content.pm.PackageManager.ApplicationInfoFlags
import android.os.Build
import android.os.Bundle
import android.view.autofill.AutofillId
-import androidx.annotation.RequiresApi
import androidx.core.net.toUri
import logcat.logcat
@@ -69,7 +68,6 @@ public sealed class FormOrigin(public open val identifier: String) {
/**
* Manages the detection of fields to fill in an [AssistStructure] and determines the [FormOrigin].
*/
-@RequiresApi(Build.VERSION_CODES.O)
private class AutofillFormParser(
context: Context,
structure: AssistStructure,
@@ -200,7 +198,6 @@ public data class Credentials(val username: String?, val password: String?, val
* Represents a collection of fields in a specific app that can be filled or saved. This is the
* entry point to all fill and save features.
*/
-@RequiresApi(Build.VERSION_CODES.O)
public class FillableForm
private constructor(
public val formOrigin: FormOrigin,
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillHelper.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillHelper.kt
index 9ff646c9..b177b5c0 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillHelper.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillHelper.kt
@@ -15,7 +15,6 @@ import android.service.autofill.SaveCallback
import android.util.Base64
import android.view.autofill.AutofillId
import android.widget.Toast
-import androidx.annotation.RequiresApi
import java.security.MessageDigest
import logcat.LogPriority.ERROR
import logcat.logcat
@@ -56,24 +55,22 @@ public fun computeCertificatesHash(context: Context, appPackage: String): String
.signatures
.orEmpty()
val stableHashOld = stableHash(signaturesOld.map { it.toByteArray() })
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- val info =
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- context.packageManager.getPackageInfo(
- appPackage,
- PackageManager.PackageInfoFlags.of(PackageManager.GET_SIGNING_CERTIFICATES.toLong()),
- )
- } else {
- context.packageManager.getPackageInfo(appPackage, PackageManager.GET_SIGNING_CERTIFICATES)
- }
- val signaturesNew =
- info.signingInfo?.signingCertificateHistory ?: info.signingInfo?.apkContentsSigners.orEmpty()
- val stableHashNew = stableHash(signaturesNew.map { it.toByteArray() })
- if (stableHashNew != stableHashOld)
- logcat("CertificatesHash", ERROR) {
- "Mismatch between old and new hash: $stableHashNew != $stableHashOld"
- }
- }
+ val info =
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ context.packageManager.getPackageInfo(
+ appPackage,
+ PackageManager.PackageInfoFlags.of(PackageManager.GET_SIGNING_CERTIFICATES.toLong()),
+ )
+ } else {
+ context.packageManager.getPackageInfo(appPackage, PackageManager.GET_SIGNING_CERTIFICATES)
+ }
+ val signaturesNew =
+ info.signingInfo?.signingCertificateHistory ?: info.signingInfo?.apkContentsSigners.orEmpty()
+ val stableHashNew = stableHash(signaturesNew.map { it.toByteArray() })
+ if (stableHashNew != stableHashOld)
+ logcat("CertificatesHash", ERROR) {
+ "Mismatch between old and new hash: $stableHashNew != $stableHashOld"
+ }
return stableHashOld
}
@@ -82,15 +79,12 @@ public fun computeCertificatesHash(context: Context, appPackage: String): String
* its `webDomain` and `webScheme`, if available.
*/
internal val AssistStructure.ViewNode.webOrigin: String?
- @RequiresApi(Build.VERSION_CODES.O)
get() =
webDomain?.let { domain ->
- val scheme =
- (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) webScheme else null) ?: "https"
+ val scheme = webScheme ?: "https"
"$scheme://$domain"
}
-@RequiresApi(Build.VERSION_CODES.O)
public class FixedSaveCallback(private val context: Context, private val callback: SaveCallback) {
private val applicationContext = context.applicationContext
@@ -120,13 +114,7 @@ public class FixedSaveCallback(private val context: Context, private val callbac
applicationContext.startIntentSender(intentSender, null, 0, 0, 0, options)
callback.onSuccess()
}
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.P -> callback.onSuccess(intentSender)
- else -> {
- callback.onSuccess()
- // On SDKs < 28, we cannot advise the Autofill framework to launch the save intent in
- // the context of the app that triggered the save request. Hence, we launch it here.
- applicationContext.startIntentSender(intentSender, null, 0, 0, 0)
- }
+ else -> callback.onSuccess(intentSender)
}
}
}
@@ -147,7 +135,6 @@ private fun visitViewNode(
}
}
-@RequiresApi(Build.VERSION_CODES.O)
internal fun AssistStructure.findNodeByAutofillId(
autofillId: AutofillId
): AssistStructure.ViewNode? {
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillScenario.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillScenario.kt
index 8a5b7fe3..15faabde 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillScenario.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillScenario.kt
@@ -11,7 +11,6 @@ import android.service.autofill.Dataset
import android.service.autofill.Field
import android.view.autofill.AutofillId
import android.view.autofill.AutofillValue
-import androidx.annotation.RequiresApi
import androidx.core.os.BundleCompat
import logcat.LogPriority.ERROR
import logcat.asLog
@@ -30,7 +29,6 @@ public enum class AutofillAction {
* [FormField], [AssistStructure.ViewNode] or [AutofillId], depending on how much metadata about the
* field is needed and available in the particular situation.
*/
-@RequiresApi(Build.VERSION_CODES.O)
public sealed class AutofillScenario<out T : Any> {
public companion object {
@@ -187,7 +185,6 @@ public sealed class AutofillScenario<out T : Any> {
get() = username != null
}
-@RequiresApi(Build.VERSION_CODES.O)
internal data class ClassifiedAutofillScenario<T : Any>(
override val username: T?,
override val fillUsername: Boolean,
@@ -212,7 +209,6 @@ internal data class ClassifiedAutofillScenario<T : Any>(
get() = newPassword.ifEmpty { currentPassword }
}
-@RequiresApi(Build.VERSION_CODES.O)
internal data class GenericAutofillScenario<T : Any>(
override val username: T?,
override val fillUsername: Boolean,
@@ -236,7 +232,6 @@ internal data class GenericAutofillScenario<T : Any>(
get() = genericPassword
}
-@RequiresApi(Build.VERSION_CODES.O)
internal fun AutofillScenario<FormField>.passesOriginCheck(singleOriginMode: Boolean): Boolean {
return if (singleOriginMode) {
// In single origin mode, only the browsers URL bar (which is never filled) should have
@@ -249,7 +244,6 @@ internal fun AutofillScenario<FormField>.passesOriginCheck(singleOriginMode: Boo
}
}
-@RequiresApi(Build.VERSION_CODES.O)
@JvmName("fillWithAutofillId")
public fun Dataset.Builder.fillWith(
scenario: AutofillScenario<AutofillId>,
@@ -272,7 +266,6 @@ public fun Dataset.Builder.fillWith(
}
}
-@RequiresApi(Build.VERSION_CODES.O)
internal inline fun <T : Any, S : Any> AutofillScenario<T>.map(
transform: (T) -> S
): AutofillScenario<S> {
@@ -292,7 +285,6 @@ internal inline fun <T : Any, S : Any> AutofillScenario<T>.map(
return builder.build()
}
-@RequiresApi(Build.VERSION_CODES.O)
@JvmName("toBundleAutofillId")
internal fun AutofillScenario<AutofillId>.toBundle(): Bundle =
when (this) {
@@ -321,7 +313,6 @@ internal fun AutofillScenario<AutofillId>.toBundle(): Bundle =
}
}
-@RequiresApi(Build.VERSION_CODES.O)
public fun AutofillScenario<AutofillId>.recoverNodes(
structure: AssistStructure
): AutofillScenario<AssistStructure.ViewNode>? {
@@ -329,13 +320,11 @@ public fun AutofillScenario<AutofillId>.recoverNodes(
}
public val AutofillScenario<AssistStructure.ViewNode>.usernameValue: String?
- @RequiresApi(Build.VERSION_CODES.O)
get() {
val value = username?.autofillValue ?: return null
return if (value.isText) value.textValue.toString() else null
}
public val AutofillScenario<AssistStructure.ViewNode>.passwordValue: String?
- @RequiresApi(Build.VERSION_CODES.O)
get() {
val distinctValues =
passwordFieldsToSave
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategy.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategy.kt
index bc227bad..5e1cebad 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategy.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategy.kt
@@ -4,8 +4,6 @@
*/
package com.github.androidpasswordstore.autofillparser
-import android.os.Build
-import androidx.annotation.RequiresApi
import com.github.androidpasswordstore.autofillparser.CertaintyLevel.Certain
import com.github.androidpasswordstore.autofillparser.CertaintyLevel.Likely
@@ -22,7 +20,6 @@ private inline fun <T> Pair<T, T>.none(predicate: T.() -> Boolean) =
* The strategy used to detect [AutofillScenario] s; expressed using the DSL implemented in
* [AutofillDsl].
*/
-@RequiresApi(Build.VERSION_CODES.O)
internal val autofillStrategy = strategy {
// Match two new password fields, an optional current password field right below or above, and
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategyDsl.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategyDsl.kt
index 673c7466..a9b01f25 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategyDsl.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategyDsl.kt
@@ -4,14 +4,11 @@
*/
package com.github.androidpasswordstore.autofillparser
-import android.os.Build
-import androidx.annotation.RequiresApi
import logcat.LogPriority.WARN
import logcat.logcat
@DslMarker internal annotation class AutofillDsl
-@RequiresApi(Build.VERSION_CODES.O)
internal interface FieldMatcher {
fun match(fields: List<FormField>, alreadyMatched: List<FormField>): List<FormField>?
@@ -72,7 +69,6 @@ internal interface FieldMatcher {
}
}
-@RequiresApi(Build.VERSION_CODES.O)
internal class SingleFieldMatcher(
private val take: (FormField, List<FormField>) -> Boolean,
private val tieBreakers: List<(FormField, List<FormField>) -> Boolean>,
@@ -136,7 +132,6 @@ internal class SingleFieldMatcher(
}
}
-@RequiresApi(Build.VERSION_CODES.O)
private class PairOfFieldsMatcher(
private val take: (Pair<FormField, FormField>, List<FormField>) -> Boolean,
private val tieBreakers: List<(Pair<FormField, FormField>, List<FormField>) -> Boolean>,
@@ -174,7 +169,6 @@ private class PairOfFieldsMatcher(
}
}
-@RequiresApi(Build.VERSION_CODES.O)
internal class AutofillRule
private constructor(
private val matchers: List<AutofillRuleMatcher>,
@@ -384,7 +378,6 @@ private constructor(
}
}
-@RequiresApi(Build.VERSION_CODES.O)
internal class AutofillStrategy private constructor(private val rules: List<AutofillRule>) {
@AutofillDsl
@@ -436,6 +429,5 @@ internal class AutofillStrategy private constructor(private val rules: List<Auto
}
}
-@RequiresApi(Build.VERSION_CODES.O)
internal fun strategy(block: AutofillStrategy.Builder.() -> Unit) =
AutofillStrategy.Builder().apply(block).build()
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 de28cd80..2db02f51 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
@@ -11,7 +11,6 @@ import android.content.pm.PackageManager.ResolveInfoFlags
import android.os.Build
import android.provider.Settings
import android.service.autofill.SaveInfo
-import androidx.annotation.RequiresApi
import androidx.core.net.toUri
/**
@@ -143,7 +142,6 @@ private fun getBrowserMultiOriginMethod(appPackage: String): BrowserMultiOriginM
* Some browsers may not issue save requests automatically and thus need
* `FLAG_SAVE_ON_ALL_VIEW_INVISIBLE` to be set.
*/
-@RequiresApi(Build.VERSION_CODES.O)
private val BROWSER_SAVE_FLAG =
mapOf(
"com.duckduckgo.mobile.android" to 0,
@@ -159,7 +157,6 @@ private val BROWSER_SAVE_FLAG =
"com.opera.touch" to 0,
)
-@RequiresApi(Build.VERSION_CODES.O)
private val BROWSER_SAVE_FLAG_IF_NO_ACCESSIBILITY =
mapOf(
"com.android.chrome" to SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE,
@@ -180,7 +177,6 @@ private fun isNoAccessibilityServiceEnabled(context: Context): Boolean {
.isNullOrEmpty()
}
-@RequiresApi(Build.VERSION_CODES.O)
private fun getBrowserSaveFlag(context: Context, appPackage: String): Int? =
BROWSER_SAVE_FLAG[appPackage]
?: BROWSER_SAVE_FLAG_IF_NO_ACCESSIBILITY[appPackage]?.takeIf {
@@ -192,7 +188,6 @@ internal data class BrowserAutofillSupportInfo(
val saveFlags: Int?,
)
-@RequiresApi(Build.VERSION_CODES.O)
internal fun getBrowserAutofillSupportInfoIfTrusted(
context: Context,
appPackage: String,
@@ -215,7 +210,6 @@ public enum class BrowserAutofillSupportLevel {
GeneralFillAndSave,
}
-@RequiresApi(Build.VERSION_CODES.O)
private fun getBrowserAutofillSupportLevel(
context: Context,
appPackage: String,
@@ -230,19 +224,9 @@ private fun getBrowserAutofillSupportLevel(
BrowserAutofillSupportLevel.PasswordFill
browserInfo.saveFlags == null -> BrowserAutofillSupportLevel.GeneralFill
else -> BrowserAutofillSupportLevel.GeneralFillAndSave
- }.takeUnless { supportLevel ->
- // On Android Oreo, only browsers with native Autofill support can be used with Password
- // Store
- // (compatibility mode is only available on Android Pie and higher). Since all known
- // browsers
- // with native Autofill support offer full save support as well, we reuse the list of those
- // browsers here.
- supportLevel != BrowserAutofillSupportLevel.GeneralFillAndSave &&
- Build.VERSION.SDK_INT < Build.VERSION_CODES.P
- } ?: BrowserAutofillSupportLevel.None
+ }
}
-@RequiresApi(Build.VERSION_CODES.O)
public fun getInstalledBrowsersWithAutofillSupportLevel(
context: Context
): List<Pair<String, BrowserAutofillSupportLevel>> {
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FormField.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FormField.kt
index 983a8f0a..b8df0664 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FormField.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FormField.kt
@@ -5,11 +5,9 @@
package com.github.androidpasswordstore.autofillparser
import android.app.assist.AssistStructure
-import android.os.Build
import android.text.InputType
import android.view.View
import android.view.autofill.AutofillId
-import androidx.annotation.RequiresApi
import androidx.autofill.HintConstants
import java.util.Locale
@@ -24,7 +22,6 @@ internal enum class CertaintyLevel {
* Represents a single potentially fillable or saveable field together with all meta data extracted
* from its [AssistStructure.ViewNode].
*/
-@RequiresApi(Build.VERSION_CODES.O)
internal class FormField(
node: AssistStructure.ViewNode,
private val index: Int,
@@ -91,7 +88,6 @@ internal class FormField(
.toSet()
.toList()
- @RequiresApi(Build.VERSION_CODES.O)
private fun isSupportedHint(hint: String?) = hint in HINTS_FILLABLE
private val EXCLUDED_TERMS =
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/PublicSuffixListCache.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/PublicSuffixListCache.kt
index 8eb113d5..d14358e8 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/PublicSuffixListCache.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/PublicSuffixListCache.kt
@@ -6,7 +6,6 @@ package com.github.androidpasswordstore.autofillparser
import android.content.Context
import android.net.InetAddresses
-import android.os.Build
import android.util.Patterns
import kotlinx.coroutines.runBlocking
import mozilla.components.lib.publicsuffixlist.PublicSuffixList
@@ -45,21 +44,13 @@ internal fun getPublicSuffixPlusOne(
// We do not check whether the domain actually exists (actually, not even whether its TLD
// exists). As long as we restrict ourselves to syntactically valid domain names,
// getPublicSuffixPlusOne will return non-colliding results.
- if (!Patterns.DOMAIN_NAME.matcher(domain).matches() || isNumericAddress(domain)) {
+ if (!Patterns.DOMAIN_NAME.matcher(domain).matches() || InetAddresses.isNumericAddress(domain)) {
domain
} else {
getCanonicalSuffix(context, domain, customSuffixes)
}
}
-private fun isNumericAddress(domain: String): Boolean {
- return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- InetAddresses.isNumericAddress(domain)
- } else {
- @Suppress("DEPRECATION") Patterns.IP_ADDRESS.matcher(domain).matches()
- }
-}
-
/**
* Returns:
* - [domain], if [domain] equals [suffix];
diff --git a/build-logic/src/main/kotlin/app/passwordstore/gradle/AndroidCommon.kt b/build-logic/src/main/kotlin/app/passwordstore/gradle/AndroidCommon.kt
index 94b9c112..70d48586 100644
--- a/build-logic/src/main/kotlin/app/passwordstore/gradle/AndroidCommon.kt
+++ b/build-logic/src/main/kotlin/app/passwordstore/gradle/AndroidCommon.kt
@@ -20,7 +20,7 @@ object AndroidCommon {
fun configure(project: Project) {
project.extensions.getByType(CommonExtension::class.java).apply {
compileSdk = 35
- defaultConfig.minSdk = 26
+ defaultConfig.minSdk = 31
packaging.resources.excludes.add("**/*.version")
packaging.resources.excludes.add("**/*.txt")
diff --git a/scripts/boot-emulator.sh b/scripts/boot-emulator.sh
index 910340f1..92a053f9 100755
--- a/scripts/boot-emulator.sh
+++ b/scripts/boot-emulator.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-# Creates and boots a display-less emulator (defaulting to Android 8.1, our min SDK)
+# Creates and boots a display-less emulator (defaulting to Android 12, our min SDK)
set -euo pipefail
@@ -9,8 +9,8 @@ set -euo pipefail
exit 1
}
-[ -n "${ANDROID_API_LEVEL:-}" ] || { echo "ANDROID_API_LEVEL not defined; defaulting to 26"; }
-API_LEVEL="${ANDROID_API_LEVEL:-26}"
+[ -n "${ANDROID_API_LEVEL:-}" ] || { echo "ANDROID_API_LEVEL not defined; defaulting to 31"; }
+API_LEVEL="${ANDROID_API_LEVEL:-31}"
ARCH="x86_64"
if [[ "$(uname -m)" == "arm64" && "$(uname)" == "Darwin" ]]; then
diff --git a/scripts/setup-environment.sh b/scripts/setup-environment.sh
index 30dd0c19..3c6c2fd1 100755
--- a/scripts/setup-environment.sh
+++ b/scripts/setup-environment.sh
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# Installs the latest command line tools and sets up the necessary packages for an Android emulator
-# for API level $ANDROID_API_LEVEL, or API 30 if unspecified.
+# for API level $ANDROID_API_LEVEL, or API 31 if unspecified.
set -euo pipefail
@@ -23,9 +23,9 @@ else
exit 1
fi
-[ -n "${ANDROID_API_LEVEL:-}" ] || { echo "ANDROID_API_LEVEL not defined; defaulting to 30"; }
+[ -n "${ANDROID_API_LEVEL:-}" ] || { echo "ANDROID_API_LEVEL not defined; defaulting to 31"; }
-API_LEVEL="${ANDROID_API_LEVEL:-30}"
+API_LEVEL="${ANDROID_API_LEVEL:-31}"
unzip -qo /tmp/tools.zip -d "${ANDROID_SDK_ROOT}/latest"
mkdir -p "${ANDROID_SDK_ROOT}/cmdline-tools"
diff --git a/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Theme.kt b/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Theme.kt
index 6d762fb4..a268c4b4 100644
--- a/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Theme.kt
+++ b/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Theme.kt
@@ -6,7 +6,6 @@
package app.passwordstore.ui.compose.theme
import android.app.Activity
-import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
@@ -84,7 +83,7 @@ public fun APSTheme(
) {
val colorScheme =
when {
- dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
+ dynamicColor -> {
val context = LocalContext.current
if (darkTheme) {
dynamicDarkColorScheme(context)