Fix ClipboardService crash (#1928)

* Fix clipboard service crash on API 31

* all: use ints directly for SDK version checks

I much prefer it this way
This commit is contained in:
Harsh Shandilya 2022-05-28 01:48:39 +05:30 committed by GitHub
parent fb7c81124c
commit 184391599b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 81 additions and 84 deletions

View file

@ -6,11 +6,10 @@ package dev.msfjarvis.aps.autofill.oreo.ui
import android.content.Context
import android.content.IntentSender
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
@Suppress("UNUSED_PARAMETER")
class AutofillSmsActivity : AppCompatActivity() {

View file

@ -49,7 +49,7 @@ import me.msfjarvis.openpgpktx.util.OpenPgpServiceConnection
import org.openintents.openpgp.IOpenPgpService2
import org.openintents.openpgp.OpenPgpError
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
@AndroidEntryPoint
class AutofillDecryptActivity : AppCompatActivity() {

View file

@ -38,7 +38,7 @@ import kotlinx.coroutines.withContext
import logcat.LogPriority.ERROR
import logcat.logcat
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
@AndroidEntryPoint
class AutofillDecryptActivityV2 : AppCompatActivity() {

View file

@ -44,7 +44,7 @@ import javax.inject.Inject
import logcat.LogPriority.ERROR
import logcat.logcat
@TargetApi(Build.VERSION_CODES.O)
@TargetApi(26)
@AndroidEntryPoint
class AutofillFilterView : AppCompatActivity() {

View file

@ -30,7 +30,7 @@ import dev.msfjarvis.aps.util.extensions.viewBinding
import logcat.LogPriority.ERROR
import logcat.logcat
@TargetApi(Build.VERSION_CODES.O)
@TargetApi(26)
class AutofillPublisherChangedActivity : AppCompatActivity() {
companion object {

View file

@ -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.result.contract.ActivityResultContracts.StartActivityForResult
@ -33,7 +32,7 @@ import javax.inject.Inject
import logcat.LogPriority.ERROR
import logcat.logcat
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
@AndroidEntryPoint
class AutofillSaveActivity : AppCompatActivity() {

View file

@ -239,7 +239,7 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou
action = ClipboardService.ACTION_START
putExtra(ClipboardService.EXTRA_NOTIFICATION_TIME, clearAfter)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (Build.VERSION.SDK_INT >= 26) {
startForegroundService(service)
} else {
startService(service)

View file

@ -129,7 +129,7 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
return@registerForActivityResult
}
val bitmap =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
if (Build.VERSION.SDK_INT >= 28) {
ImageDecoder.decodeBitmap(ImageDecoder.createSource(contentResolver, imageUri))
.copy(Bitmap.Config.ARGB_8888, true)
} else {

View file

@ -105,7 +105,7 @@ class PasswordCreationActivityV2 : BasePgpActivity() {
return@registerForActivityResult
}
val bitmap =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
if (Build.VERSION.SDK_INT >= 28) {
ImageDecoder.decodeBitmap(ImageDecoder.createSource(contentResolver, imageUri))
.copy(Bitmap.Config.ARGB_8888, true)
} else {

View file

@ -35,11 +35,11 @@ class AutofillSettings(private val activity: FragmentActivity) : SettingsProvide
private val isAutofillServiceEnabled: Boolean
get() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return false
if (Build.VERSION.SDK_INT < 26) return false
return activity.autofillManager?.hasEnabledAutofillServices() == true
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
private fun showAutofillDialog(pref: SwitchPreference) {
val observer = LifecycleEventObserver { _, event ->
when (event) {
@ -95,10 +95,10 @@ class AutofillSettings(private val activity: FragmentActivity) : SettingsProvide
builder.apply {
switch(PreferenceKeys.AUTOFILL_ENABLE) {
titleRes = R.string.pref_autofill_enable_title
visible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
visible = Build.VERSION.SDK_INT >= 26
defaultValue = isAutofillServiceEnabled
onClick {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return@onClick true
if (Build.VERSION.SDK_INT < 26) return@onClick true
if (isAutofillServiceEnabled) {
activity.autofillManager?.disableAutofillServices()
} else {

View file

@ -97,7 +97,7 @@ class GeneralSettings(private val activity: FragmentActivity) : SettingsProvider
}
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
if (Build.VERSION.SDK_INT >= 25) {
activity.getSystemService<ShortcutManager>()?.apply {
removeDynamicShortcuts(dynamicShortcuts.map { it.id }.toMutableList())
}

View file

@ -47,7 +47,7 @@ class MiscSettings(activity: FragmentActivity) : SettingsProvider {
putExtra("uri", uri)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (Build.VERSION.SDK_INT >= 26) {
activity.startForegroundService(service)
} else {
activity.startService(service)

View file

@ -166,7 +166,7 @@ class RepositorySettings(private val activity: FragmentActivity) : SettingsProvi
}
.onFailure { it.message?.let { message -> activity.snackbar(message = message) } }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
if (Build.VERSION.SDK_INT >= 25) {
activity.getSystemService<ShortcutManager>()?.apply {
removeDynamicShortcuts(dynamicShortcuts.map { it.id }.toMutableList())
}

View file

@ -7,7 +7,6 @@ package dev.msfjarvis.aps.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.FillResponse
@ -36,7 +35,7 @@ import logcat.asLog
import logcat.logcat
/** Implements [AutofillResponseBuilder]'s methods for API 30 and above */
@RequiresApi(Build.VERSION_CODES.R)
@RequiresApi(30)
class Api30AutofillResponseBuilder
@AssistedInject
constructor(

View file

@ -5,7 +5,6 @@
package dev.msfjarvis.aps.util.autofill
import android.content.Context
import android.os.Build
import androidx.annotation.RequiresApi
import com.github.androidpasswordstore.autofillparser.Credentials
import dev.msfjarvis.aps.data.passfile.PasswordEntry
@ -103,7 +102,7 @@ enum class DirectoryStructure(val value: String) {
?: file.nameWithoutExtension
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
fun getSaveFolderName(sanitizedIdentifier: String, username: String?) =
when (this) {
EncryptedUsername -> "/"

View file

@ -35,7 +35,7 @@ import logcat.LogPriority.ERROR
import logcat.asLog
import logcat.logcat
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
class AutofillResponseBuilder
@AssistedInject
constructor(
@ -175,7 +175,7 @@ constructor(
addDataset(it)
}
if (datasetCount == 0) return null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
if (Build.VERSION.SDK_INT >= 28) {
setHeader(
makeRemoteView(
context,
@ -218,7 +218,7 @@ constructor(
// 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) {
if (Build.VERSION.SDK_INT >= 28) {
Dataset.Builder()
} else {
Dataset.Builder(makeRemoteView(context, makeEmptyMetadata()))

View file

@ -47,7 +47,7 @@ fun makeInlinePresentation(
imeSpec: InlinePresentationSpec,
metadata: DatasetMetadata
): InlinePresentation? {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return null
if (Build.VERSION.SDK_INT < 30) return null
if (UiVersions.INLINE_UI_VERSION_1 !in UiVersions.getVersions(imeSpec.style)) return null

View file

@ -11,7 +11,6 @@ import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.os.Build
import android.util.Base64
import android.util.TypedValue
import android.view.View
@ -33,7 +32,7 @@ import logcat.logcat
/** Get an instance of [AutofillManager]. Only available on Android Oreo and above */
val Context.autofillManager: AutofillManager?
@RequiresApi(Build.VERSION_CODES.O) get() = getSystemService()
@RequiresApi(26) get() = getSystemService()
/** Get an instance of [ClipboardManager] */
val Context.clipboard

View file

@ -120,7 +120,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)
if (Build.VERSION.SDK_INT >= 28)
context.packageManager.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)
else false
}
@ -162,7 +162,7 @@ object SshKey {
setKeySize(256)
setAlgorithmParameterSpec(java.security.spec.ECGenParameterSpec("secp256r1"))
setDigests(KeyProperties.DIGEST_SHA256)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
if (Build.VERSION.SDK_INT >= 28) {
setIsStrongBoxBacked(isStrongBoxSupported)
}
}
@ -284,7 +284,7 @@ object SshKey {
apply(algorithm.applyToSpec)
if (requireAuthentication) {
setUserAuthenticationRequired(true)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (Build.VERSION.SDK_INT >= 30) {
setUserAuthenticationParameters(30, KeyProperties.AUTH_DEVICE_CREDENTIAL)
} else {
@Suppress("DEPRECATION") setUserAuthenticationValidityDurationSeconds(30)

View file

@ -112,8 +112,17 @@ class ClipboardService : Service() {
val clearTimeMs = clearTime * 1000L
val clearIntent = Intent(this, ClipboardService::class.java).apply { action = ACTION_CLEAR }
val pendingIntent =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
PendingIntent.getForegroundService(this, 0, clearIntent, PendingIntent.FLAG_UPDATE_CURRENT)
if (Build.VERSION.SDK_INT >= 26) {
PendingIntent.getForegroundService(
this,
0,
clearIntent,
if (Build.VERSION.SDK_INT >= 31) {
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
)
} else {
PendingIntent.getService(
this,
@ -127,7 +136,7 @@ class ClipboardService : Service() {
)
}
val notification =
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
if (Build.VERSION.SDK_INT <= 23) {
createNotificationApi23(pendingIntent)
} else {
createNotificationApi24(pendingIntent, clearTimeMs)
@ -148,7 +157,7 @@ class ClipboardService : Service() {
.build()
}
@RequiresApi(Build.VERSION_CODES.N)
@RequiresApi(24)
private fun createNotificationApi24(
pendingIntent: PendingIntent,
clearTimeMs: Long
@ -167,7 +176,7 @@ class ClipboardService : Service() {
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (Build.VERSION.SDK_INT >= 26) {
val serviceChannel =
NotificationChannel(
CHANNEL_ID,

View file

@ -37,7 +37,7 @@ import javax.inject.Inject
import logcat.LogPriority.ERROR
import logcat.logcat
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
@AndroidEntryPoint
class OreoAutofillService : AutofillService() {
@ -102,7 +102,7 @@ class OreoAutofillService : AutofillService() {
callback.onSuccess(null)
return
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (Build.VERSION.SDK_INT >= 30) {
api30ResponseBuilderFactory
.create(formToFill)
.fillCredentials(this, request.inlineSuggestionsRequest, callback)

View file

@ -65,7 +65,7 @@ class PasswordExportService : Service() {
logcat { "Copying ${repositoryDirectory.path} to $targetDirectory" }
val dateString =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (Build.VERSION.SDK_INT >= 26) {
LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME)
} else {
String.format("%tFT%<tRZ", Calendar.getInstance(TimeZone.getTimeZone("Z")))
@ -135,7 +135,7 @@ class PasswordExportService : Service() {
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (Build.VERSION.SDK_INT >= 26) {
val serviceChannel =
NotificationChannel(
CHANNEL_ID,

View file

@ -42,7 +42,7 @@ constructor(
* [MAX_SHORTCUT_COUNT] and older items are removed by a simple LRU sweep.
*/
fun addDynamicShortcut(item: PasswordItem, intent: Intent) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) return
if (Build.VERSION.SDK_INT < 25) return
val shortcutManager: ShortcutManager = context.getSystemService() ?: return
val shortcut = buildShortcut(item, intent)
val shortcuts = shortcutManager.dynamicShortcuts
@ -67,7 +67,7 @@ constructor(
* a no-op if the user's default launcher does not support pinned shortcuts.
*/
fun addPinnedShortcut(item: PasswordItem, intent: Intent) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
if (Build.VERSION.SDK_INT < 26) return
val shortcutManager: ShortcutManager = context.getSystemService() ?: return
if (!shortcutManager.isRequestPinShortcutSupported) {
logcat { "addPinnedShortcut: pin shortcuts unsupported" }
@ -78,7 +78,7 @@ constructor(
}
/** Creates a [ShortcutInfo] from [item] and assigns [intent] to it. */
@RequiresApi(Build.VERSION_CODES.N_MR1)
@RequiresApi(25)
private fun buildShortcut(item: PasswordItem, intent: Intent): ShortcutInfo {
return ShortcutInfo.Builder(context, item.fullPathToParent)
.setShortLabel(item.toString())
@ -93,7 +93,7 @@ constructor(
* data, which ensures that the get/set dance in [addDynamicShortcut] does not cause invalidation
* of icon assets, resulting in invisible icons in all but the newest launcher shortcut.
*/
@RequiresApi(Build.VERSION_CODES.N_MR1)
@RequiresApi(25)
private fun rebuildShortcut(shortcut: ShortcutInfo): ShortcutInfo {
// Non-null assertions are fine since we know these values aren't null.
return ShortcutInfo.Builder(context, shortcut.id)

View file

@ -52,7 +52,7 @@ suspend fun <T> Task<T>.suspendableAwait() =
}
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
class AutofillSmsActivity : AppCompatActivity() {
companion object {
@ -60,7 +60,7 @@ class AutofillSmsActivity : AppCompatActivity() {
private var fillOtpFromSmsRequestCode = 1
fun shouldOfferFillFromSms(context: Context): Boolean {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return false
if (Build.VERSION.SDK_INT < 28) return false
val googleApiAvailabilityInstance = GoogleApiAvailability.getInstance()
val googleApiStatus = googleApiAvailabilityInstance.isGooglePlayServicesAvailable(context)
if (googleApiStatus != ConnectionResult.SUCCESS) {

View file

@ -8,7 +8,6 @@ import android.app.assist.AssistStructure
import android.content.Context
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.view.autofill.AutofillId
import androidx.annotation.RequiresApi
@ -60,7 +59,7 @@ 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)
@RequiresApi(26)
private class AutofillFormParser(
context: Context,
structure: AssistStructure,
@ -191,7 +190,7 @@ 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)
@RequiresApi(26)
public class FillableForm
private constructor(
public val formOrigin: FormOrigin,

View file

@ -71,14 +71,14 @@ 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)
@RequiresApi(26)
get() =
webDomain?.let { domain ->
val scheme = (if (Build.VERSION.SDK_INT >= 28) webScheme else null) ?: "https"
"$scheme://$domain"
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
public class FixedSaveCallback(context: Context, private val callback: SaveCallback) {
private val applicationContext = context.applicationContext
@ -121,7 +121,7 @@ private fun visitViewNode(
}
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
internal fun AssistStructure.findNodeByAutofillId(
autofillId: AutofillId
): AssistStructure.ViewNode? {

View file

@ -5,7 +5,6 @@
package com.github.androidpasswordstore.autofillparser
import android.app.assist.AssistStructure
import android.os.Build
import android.os.Bundle
import android.service.autofill.Dataset
import android.view.autofill.AutofillId
@ -28,7 +27,7 @@ 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)
@RequiresApi(26)
public sealed class AutofillScenario<out T : Any> {
public companion object {
@ -163,7 +162,7 @@ public sealed class AutofillScenario<out T : Any> {
get() = username != null
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
internal data class ClassifiedAutofillScenario<T : Any>(
override val username: T?,
override val fillUsername: Boolean,
@ -184,7 +183,7 @@ internal data class ClassifiedAutofillScenario<T : Any>(
get() = newPassword.ifEmpty { currentPassword }
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
internal data class GenericAutofillScenario<T : Any>(
override val username: T?,
override val fillUsername: Boolean,
@ -204,7 +203,7 @@ internal data class GenericAutofillScenario<T : Any>(
get() = genericPassword
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
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
@ -217,7 +216,7 @@ internal fun AutofillScenario<FormField>.passesOriginCheck(singleOriginMode: Boo
}
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
@JvmName("fillWithAutofillId")
public fun Dataset.Builder.fillWith(
scenario: AutofillScenario<AutofillId>,
@ -236,7 +235,7 @@ public fun Dataset.Builder.fillWith(
}
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
internal inline fun <T : Any, S : Any> AutofillScenario<T>.map(
transform: (T) -> S
): AutofillScenario<S> {
@ -256,7 +255,7 @@ internal inline fun <T : Any, S : Any> AutofillScenario<T>.map(
return builder.build()
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
@JvmName("toBundleAutofillId")
internal fun AutofillScenario<AutofillId>.toBundle(): Bundle =
when (this) {
@ -285,7 +284,7 @@ internal fun AutofillScenario<AutofillId>.toBundle(): Bundle =
}
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
public fun AutofillScenario<AutofillId>.recoverNodes(
structure: AssistStructure
): AutofillScenario<AssistStructure.ViewNode>? {
@ -293,13 +292,13 @@ public fun AutofillScenario<AutofillId>.recoverNodes(
}
public val AutofillScenario<AssistStructure.ViewNode>.usernameValue: String?
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
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)
@RequiresApi(26)
get() {
val distinctValues =
passwordFieldsToSave

View file

@ -4,7 +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 +21,7 @@ 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)
@RequiresApi(26)
internal val autofillStrategy = strategy {
// Match two new password fields, an optional current password field right below or above, and

View file

@ -4,14 +4,13 @@
*/
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)
@RequiresApi(26)
internal interface FieldMatcher {
fun match(fields: List<FormField>, alreadyMatched: List<FormField>): List<FormField>?
@ -72,7 +71,7 @@ internal interface FieldMatcher {
}
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
internal class SingleFieldMatcher(
private val take: (FormField, List<FormField>) -> Boolean,
private val tieBreakers: List<(FormField, List<FormField>) -> Boolean>
@ -136,7 +135,7 @@ internal class SingleFieldMatcher(
}
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
private class PairOfFieldsMatcher(
private val take: (Pair<FormField, FormField>, List<FormField>) -> Boolean,
private val tieBreakers: List<(Pair<FormField, FormField>, List<FormField>) -> Boolean>
@ -174,7 +173,7 @@ private class PairOfFieldsMatcher(
}
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
internal class AutofillRule
private constructor(
private val matchers: List<AutofillRuleMatcher>,
@ -382,7 +381,7 @@ private constructor(
}
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
internal class AutofillStrategy private constructor(private val rules: List<AutofillRule>) {
@AutofillDsl
@ -435,6 +434,6 @@ internal class AutofillStrategy private constructor(private val rules: List<Auto
}
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
internal fun strategy(block: AutofillStrategy.Builder.() -> Unit) =
AutofillStrategy.Builder().apply(block).build()

View file

@ -142,7 +142,7 @@ 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)
@RequiresApi(26)
private val BROWSER_SAVE_FLAG =
mapOf(
"com.duckduckgo.mobile.android" to 0,
@ -156,7 +156,7 @@ private val BROWSER_SAVE_FLAG =
"com.opera.touch" to 0,
)
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
private val BROWSER_SAVE_FLAG_IF_NO_ACCESSIBILITY =
mapOf(
"com.android.chrome" to SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE,
@ -176,7 +176,7 @@ private fun isNoAccessibilityServiceEnabled(context: Context): Boolean {
.isNullOrEmpty()
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
private fun getBrowserSaveFlag(context: Context, appPackage: String): Int? =
BROWSER_SAVE_FLAG[appPackage]
?: BROWSER_SAVE_FLAG_IF_NO_ACCESSIBILITY[appPackage]?.takeIf {
@ -188,7 +188,7 @@ internal data class BrowserAutofillSupportInfo(
val saveFlags: Int?
)
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
internal fun getBrowserAutofillSupportInfoIfTrusted(
context: Context,
appPackage: String
@ -214,7 +214,7 @@ public enum class BrowserAutofillSupportLevel {
GeneralFillAndSave,
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
private fun getBrowserAutofillSupportLevel(
context: Context,
appPackage: String
@ -234,13 +234,12 @@ private fun getBrowserAutofillSupportLevel(
// (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
supportLevel != BrowserAutofillSupportLevel.GeneralFillAndSave && Build.VERSION.SDK_INT < 28
}
?: BrowserAutofillSupportLevel.None
}
@RequiresApi(Build.VERSION_CODES.O)
@RequiresApi(26)
public fun getInstalledBrowsersWithAutofillSupportLevel(
context: Context
): List<Pair<String, BrowserAutofillSupportLevel>> {

View file

@ -5,7 +5,6 @@
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
@ -24,7 +23,7 @@ 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)
@RequiresApi(26)
internal class FormField(
node: AssistStructure.ViewNode,
private val index: Int,
@ -114,8 +113,7 @@ internal class FormField(
.toSet()
.toList()
@RequiresApi(Build.VERSION_CODES.O)
private fun isSupportedHint(hint: String?) = hint in HINTS_FILLABLE
@RequiresApi(26) private fun isSupportedHint(hint: String?) = hint in HINTS_FILLABLE
private val EXCLUDED_TERMS =
listOf(
"url_bar", // Chrome/Edge/Firefox address bar