Begin cleaning up Detekt warnings (#2027)
This commit is contained in:
parent
9a3c182348
commit
6d0bff144c
35 changed files with 96 additions and 140 deletions
|
@ -6,10 +6,11 @@ package app.passwordstore.autofill.oreo.ui
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.IntentSender
|
import android.content.IntentSender
|
||||||
|
import android.os.Build
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
class AutofillSmsActivity : AppCompatActivity() {
|
class AutofillSmsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ import kotlinx.coroutines.withContext
|
||||||
import logcat.LogPriority.ERROR
|
import logcat.LogPriority.ERROR
|
||||||
import logcat.logcat
|
import logcat.logcat
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class AutofillDecryptActivity : AppCompatActivity() {
|
class AutofillDecryptActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ class AutofillDecryptActivity : AppCompatActivity() {
|
||||||
context,
|
context,
|
||||||
decryptFileRequestCode++,
|
decryptFileRequestCode++,
|
||||||
intent,
|
intent,
|
||||||
if (Build.VERSION.SDK_INT >= 31) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE
|
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE
|
||||||
} else {
|
} else {
|
||||||
PendingIntent.FLAG_CANCEL_CURRENT
|
PendingIntent.FLAG_CANCEL_CURRENT
|
||||||
|
|
|
@ -41,7 +41,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||||
import logcat.LogPriority.ERROR
|
import logcat.LogPriority.ERROR
|
||||||
import logcat.logcat
|
import logcat.logcat
|
||||||
|
|
||||||
@TargetApi(26)
|
@TargetApi(Build.VERSION_CODES.O)
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class AutofillFilterView : AppCompatActivity() {
|
class AutofillFilterView : AppCompatActivity() {
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ class AutofillFilterView : AppCompatActivity() {
|
||||||
context,
|
context,
|
||||||
matchAndDecryptFileRequestCode++,
|
matchAndDecryptFileRequestCode++,
|
||||||
intent,
|
intent,
|
||||||
if (Build.VERSION.SDK_INT >= 31) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE
|
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE
|
||||||
} else {
|
} else {
|
||||||
PendingIntent.FLAG_CANCEL_CURRENT
|
PendingIntent.FLAG_CANCEL_CURRENT
|
||||||
|
|
|
@ -33,7 +33,7 @@ import com.github.michaelbull.result.runCatching
|
||||||
import logcat.LogPriority.ERROR
|
import logcat.LogPriority.ERROR
|
||||||
import logcat.logcat
|
import logcat.logcat
|
||||||
|
|
||||||
@TargetApi(26)
|
@TargetApi(Build.VERSION_CODES.O)
|
||||||
class AutofillPublisherChangedActivity : AppCompatActivity() {
|
class AutofillPublisherChangedActivity : AppCompatActivity() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -57,7 +57,7 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
|
||||||
context,
|
context,
|
||||||
publisherChangedRequestCode++,
|
publisherChangedRequestCode++,
|
||||||
intent,
|
intent,
|
||||||
if (Build.VERSION.SDK_INT >= 31) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE
|
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE
|
||||||
} else {
|
} else {
|
||||||
PendingIntent.FLAG_CANCEL_CURRENT
|
PendingIntent.FLAG_CANCEL_CURRENT
|
||||||
|
|
|
@ -8,6 +8,7 @@ import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentSender
|
import android.content.IntentSender
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.autofill.AutofillManager
|
import android.view.autofill.AutofillManager
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
||||||
|
@ -28,7 +29,7 @@ import java.io.File
|
||||||
import logcat.LogPriority.ERROR
|
import logcat.LogPriority.ERROR
|
||||||
import logcat.logcat
|
import logcat.logcat
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class AutofillSaveActivity : AppCompatActivity() {
|
class AutofillSaveActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ open class BasePgpActivity : AppCompatActivity() {
|
||||||
action = ClipboardService.ACTION_START
|
action = ClipboardService.ACTION_START
|
||||||
putExtra(ClipboardService.EXTRA_NOTIFICATION_TIME, clearAfter)
|
putExtra(ClipboardService.EXTRA_NOTIFICATION_TIME, clearAfter)
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= 26) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
startForegroundService(service)
|
startForegroundService(service)
|
||||||
} else {
|
} else {
|
||||||
startService(service)
|
startService(service)
|
||||||
|
|
|
@ -105,7 +105,7 @@ class PasswordCreationActivity : BasePgpActivity() {
|
||||||
return@registerForActivityResult
|
return@registerForActivityResult
|
||||||
}
|
}
|
||||||
val bitmap =
|
val bitmap =
|
||||||
if (Build.VERSION.SDK_INT >= 28) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
ImageDecoder.decodeBitmap(ImageDecoder.createSource(contentResolver, imageUri))
|
ImageDecoder.decodeBitmap(ImageDecoder.createSource(contentResolver, imageUri))
|
||||||
.copy(Bitmap.Config.ARGB_8888, true)
|
.copy(Bitmap.Config.ARGB_8888, true)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -62,7 +62,7 @@ class ProxySelectorActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isNumericAddress(text: CharSequence): Boolean {
|
private fun isNumericAddress(text: CharSequence): Boolean {
|
||||||
return if (Build.VERSION.SDK_INT >= 29) {
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
InetAddresses.isNumericAddress(text as String)
|
InetAddresses.isNumericAddress(text as String)
|
||||||
} else {
|
} else {
|
||||||
@Suppress("DEPRECATION") Patterns.IP_ADDRESS.matcher(text).matches()
|
@Suppress("DEPRECATION") Patterns.IP_ADDRESS.matcher(text).matches()
|
||||||
|
|
|
@ -35,11 +35,11 @@ class AutofillSettings(private val activity: FragmentActivity) : SettingsProvide
|
||||||
|
|
||||||
private val isAutofillServiceEnabled: Boolean
|
private val isAutofillServiceEnabled: Boolean
|
||||||
get() {
|
get() {
|
||||||
if (Build.VERSION.SDK_INT < 26) return false
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return false
|
||||||
return activity.autofillManager?.hasEnabledAutofillServices() == true
|
return activity.autofillManager?.hasEnabledAutofillServices() == true
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
private fun showAutofillDialog(pref: SwitchPreference) {
|
private fun showAutofillDialog(pref: SwitchPreference) {
|
||||||
val observer = LifecycleEventObserver { _, event ->
|
val observer = LifecycleEventObserver { _, event ->
|
||||||
when (event) {
|
when (event) {
|
||||||
|
@ -95,10 +95,10 @@ class AutofillSettings(private val activity: FragmentActivity) : SettingsProvide
|
||||||
builder.apply {
|
builder.apply {
|
||||||
switch(PreferenceKeys.AUTOFILL_ENABLE) {
|
switch(PreferenceKeys.AUTOFILL_ENABLE) {
|
||||||
titleRes = R.string.pref_autofill_enable_title
|
titleRes = R.string.pref_autofill_enable_title
|
||||||
visible = Build.VERSION.SDK_INT >= 26
|
visible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||||
defaultValue = isAutofillServiceEnabled
|
defaultValue = isAutofillServiceEnabled
|
||||||
onClick {
|
onClick {
|
||||||
if (Build.VERSION.SDK_INT < 26) return@onClick true
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return@onClick true
|
||||||
if (isAutofillServiceEnabled) {
|
if (isAutofillServiceEnabled) {
|
||||||
activity.autofillManager?.disableAutofillServices()
|
activity.autofillManager?.disableAutofillServices()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -97,7 +97,7 @@ class GeneralSettings(private val activity: FragmentActivity) : SettingsProvider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= 25) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||||
activity.getSystemService<ShortcutManager>()?.apply {
|
activity.getSystemService<ShortcutManager>()?.apply {
|
||||||
removeDynamicShortcuts(dynamicShortcuts.map { it.id }.toMutableList())
|
removeDynamicShortcuts(dynamicShortcuts.map { it.id }.toMutableList())
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ class MiscSettings(activity: FragmentActivity) : SettingsProvider {
|
||||||
putExtra("uri", uri)
|
putExtra("uri", uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 26) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
activity.startForegroundService(service)
|
activity.startForegroundService(service)
|
||||||
} else {
|
} else {
|
||||||
activity.startService(service)
|
activity.startService(service)
|
||||||
|
|
|
@ -166,7 +166,7 @@ class RepositorySettings(private val activity: FragmentActivity) : SettingsProvi
|
||||||
}
|
}
|
||||||
.onFailure { it.message?.let { message -> activity.snackbar(message = message) } }
|
.onFailure { it.message?.let { message -> activity.snackbar(message = message) } }
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 25) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||||
activity.getSystemService<ShortcutManager>()?.apply {
|
activity.getSystemService<ShortcutManager>()?.apply {
|
||||||
removeDynamicShortcuts(dynamicShortcuts.map { it.id }.toMutableList())
|
removeDynamicShortcuts(dynamicShortcuts.map { it.id }.toMutableList())
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ import logcat.asLog
|
||||||
import logcat.logcat
|
import logcat.logcat
|
||||||
|
|
||||||
/** Implements [AutofillResponseBuilder]'s methods for API 30 and above */
|
/** Implements [AutofillResponseBuilder]'s methods for API 30 and above */
|
||||||
@RequiresApi(30)
|
@RequiresApi(Build.VERSION_CODES.R)
|
||||||
class Api30AutofillResponseBuilder
|
class Api30AutofillResponseBuilder
|
||||||
@AssistedInject
|
@AssistedInject
|
||||||
constructor(
|
constructor(
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package app.passwordstore.util.autofill
|
package app.passwordstore.util.autofill
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import app.passwordstore.data.passfile.PasswordEntry
|
import app.passwordstore.data.passfile.PasswordEntry
|
||||||
import app.passwordstore.util.extensions.getString
|
import app.passwordstore.util.extensions.getString
|
||||||
|
@ -102,7 +103,7 @@ enum class DirectoryStructure(val value: String) {
|
||||||
?: file.nameWithoutExtension
|
?: file.nameWithoutExtension
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
fun getSaveFolderName(sanitizedIdentifier: String, username: String?) =
|
fun getSaveFolderName(sanitizedIdentifier: String, username: String?) =
|
||||||
when (this) {
|
when (this) {
|
||||||
EncryptedUsername -> "/"
|
EncryptedUsername -> "/"
|
||||||
|
|
|
@ -32,7 +32,7 @@ import logcat.LogPriority.ERROR
|
||||||
import logcat.asLog
|
import logcat.asLog
|
||||||
import logcat.logcat
|
import logcat.logcat
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
class AutofillResponseBuilder
|
class AutofillResponseBuilder
|
||||||
@AssistedInject
|
@AssistedInject
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -167,7 +167,7 @@ constructor(
|
||||||
addDataset(it)
|
addDataset(it)
|
||||||
}
|
}
|
||||||
if (datasetCount == 0) return null
|
if (datasetCount == 0) return null
|
||||||
if (Build.VERSION.SDK_INT >= 28) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
setHeader(
|
setHeader(
|
||||||
makeRemoteView(
|
makeRemoteView(
|
||||||
context,
|
context,
|
||||||
|
@ -210,7 +210,7 @@ constructor(
|
||||||
// fill-in dataset without any visual representation. This causes it to be missing from
|
// 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.
|
// the Autofill suggestions shown after the user clears the filled out form fields.
|
||||||
val builder =
|
val builder =
|
||||||
if (Build.VERSION.SDK_INT >= 28) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
Dataset.Builder()
|
Dataset.Builder()
|
||||||
} else {
|
} else {
|
||||||
@Suppress("DEPRECATION") Dataset.Builder(makeRemoteView(context, makeEmptyMetadata()))
|
@Suppress("DEPRECATION") Dataset.Builder(makeRemoteView(context, makeEmptyMetadata()))
|
||||||
|
|
|
@ -47,7 +47,7 @@ fun makeInlinePresentation(
|
||||||
imeSpec: InlinePresentationSpec,
|
imeSpec: InlinePresentationSpec,
|
||||||
metadata: DatasetMetadata
|
metadata: DatasetMetadata
|
||||||
): InlinePresentation? {
|
): InlinePresentation? {
|
||||||
if (Build.VERSION.SDK_INT < 30) return null
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return null
|
||||||
|
|
||||||
if (UiVersions.INLINE_UI_VERSION_1 !in UiVersions.getVersions(imeSpec.style)) return null
|
if (UiVersions.INLINE_UI_VERSION_1 !in UiVersions.getVersions(imeSpec.style)) return null
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ fun makeInlinePresentation(
|
||||||
context,
|
context,
|
||||||
0,
|
0,
|
||||||
Intent(context, PasswordStore::class.java),
|
Intent(context, PasswordStore::class.java),
|
||||||
if (Build.VERSION.SDK_INT >= 31) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
PendingIntent.FLAG_MUTABLE
|
PendingIntent.FLAG_MUTABLE
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
|
|
|
@ -40,7 +40,7 @@ import logcat.logcat
|
||||||
|
|
||||||
/** Get an instance of [AutofillManager]. Only available on Android Oreo and above */
|
/** Get an instance of [AutofillManager]. Only available on Android Oreo and above */
|
||||||
val Context.autofillManager: AutofillManager?
|
val Context.autofillManager: AutofillManager?
|
||||||
@RequiresApi(26) get() = getSystemService()
|
@RequiresApi(Build.VERSION_CODES.O) get() = getSystemService()
|
||||||
|
|
||||||
/** Get an instance of [ClipboardManager] */
|
/** Get an instance of [ClipboardManager] */
|
||||||
val Context.clipboard
|
val Context.clipboard
|
||||||
|
|
|
@ -120,7 +120,7 @@ object SshKey {
|
||||||
context.sharedPrefs.edit { putString(PreferenceKeys.GIT_REMOTE_KEY_TYPE, value?.value) }
|
context.sharedPrefs.edit { putString(PreferenceKeys.GIT_REMOTE_KEY_TYPE, value?.value) }
|
||||||
|
|
||||||
private val isStrongBoxSupported by unsafeLazy {
|
private val isStrongBoxSupported by unsafeLazy {
|
||||||
if (Build.VERSION.SDK_INT >= 28)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
||||||
context.packageManager.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)
|
context.packageManager.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)
|
||||||
else false
|
else false
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ object SshKey {
|
||||||
setKeySize(256)
|
setKeySize(256)
|
||||||
setAlgorithmParameterSpec(java.security.spec.ECGenParameterSpec("secp256r1"))
|
setAlgorithmParameterSpec(java.security.spec.ECGenParameterSpec("secp256r1"))
|
||||||
setDigests(KeyProperties.DIGEST_SHA256)
|
setDigests(KeyProperties.DIGEST_SHA256)
|
||||||
if (Build.VERSION.SDK_INT >= 28) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
setIsStrongBoxBacked(isStrongBoxSupported)
|
setIsStrongBoxBacked(isStrongBoxSupported)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,7 +285,7 @@ object SshKey {
|
||||||
apply(algorithm.applyToSpec)
|
apply(algorithm.applyToSpec)
|
||||||
if (requireAuthentication) {
|
if (requireAuthentication) {
|
||||||
setUserAuthenticationRequired(true)
|
setUserAuthenticationRequired(true)
|
||||||
if (Build.VERSION.SDK_INT >= 30) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
setUserAuthenticationParameters(30, KeyProperties.AUTH_DEVICE_CREDENTIAL)
|
setUserAuthenticationParameters(30, KeyProperties.AUTH_DEVICE_CREDENTIAL)
|
||||||
} else {
|
} else {
|
||||||
@Suppress("DEPRECATION") setUserAuthenticationValidityDurationSeconds(30)
|
@Suppress("DEPRECATION") setUserAuthenticationValidityDurationSeconds(30)
|
||||||
|
|
|
@ -120,12 +120,12 @@ class ClipboardService : Service() {
|
||||||
val clearTimeMs = clearTime * 1000L
|
val clearTimeMs = clearTime * 1000L
|
||||||
val clearIntent = Intent(this, ClipboardService::class.java).apply { action = ACTION_CLEAR }
|
val clearIntent = Intent(this, ClipboardService::class.java).apply { action = ACTION_CLEAR }
|
||||||
val pendingIntent =
|
val pendingIntent =
|
||||||
if (Build.VERSION.SDK_INT >= 26) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
PendingIntent.getForegroundService(
|
PendingIntent.getForegroundService(
|
||||||
this,
|
this,
|
||||||
0,
|
0,
|
||||||
clearIntent,
|
clearIntent,
|
||||||
if (Build.VERSION.SDK_INT >= 31) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
|
||||||
} else {
|
} else {
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT
|
PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
@ -136,7 +136,7 @@ class ClipboardService : Service() {
|
||||||
this,
|
this,
|
||||||
0,
|
0,
|
||||||
clearIntent,
|
clearIntent,
|
||||||
if (Build.VERSION.SDK_INT >= 31) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
|
||||||
} else {
|
} else {
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT
|
PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
@ -144,7 +144,7 @@ class ClipboardService : Service() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val notification =
|
val notification =
|
||||||
if (Build.VERSION.SDK_INT <= 23) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O) {
|
||||||
createNotificationApi23(pendingIntent)
|
createNotificationApi23(pendingIntent)
|
||||||
} else {
|
} else {
|
||||||
createNotificationApi24(pendingIntent, clearTimeMs)
|
createNotificationApi24(pendingIntent, clearTimeMs)
|
||||||
|
@ -165,7 +165,7 @@ class ClipboardService : Service() {
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(24)
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
private fun createNotificationApi24(
|
private fun createNotificationApi24(
|
||||||
pendingIntent: PendingIntent,
|
pendingIntent: PendingIntent,
|
||||||
clearTimeMs: Long
|
clearTimeMs: Long
|
||||||
|
@ -184,7 +184,7 @@ class ClipboardService : Service() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createNotificationChannel() {
|
private fun createNotificationChannel() {
|
||||||
if (Build.VERSION.SDK_INT >= 26) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val serviceChannel =
|
val serviceChannel =
|
||||||
NotificationChannel(
|
NotificationChannel(
|
||||||
CHANNEL_ID,
|
CHANNEL_ID,
|
||||||
|
|
|
@ -37,7 +37,7 @@ import javax.inject.Inject
|
||||||
import logcat.LogPriority.ERROR
|
import logcat.LogPriority.ERROR
|
||||||
import logcat.logcat
|
import logcat.logcat
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class OreoAutofillService : AutofillService() {
|
class OreoAutofillService : AutofillService() {
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ class OreoAutofillService : AutofillService() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (structure.activityComponent.packageName in DENYLISTED_PACKAGES) {
|
if (structure.activityComponent.packageName in DENYLISTED_PACKAGES) {
|
||||||
if (Build.VERSION.SDK_INT >= 28) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
callback.onSuccess(
|
callback.onSuccess(
|
||||||
FillResponse.Builder().run {
|
FillResponse.Builder().run {
|
||||||
disableAutofill(DISABLE_AUTOFILL_DURATION_MS)
|
disableAutofill(DISABLE_AUTOFILL_DURATION_MS)
|
||||||
|
@ -102,7 +102,7 @@ class OreoAutofillService : AutofillService() {
|
||||||
callback.onSuccess(null)
|
callback.onSuccess(null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= 30) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
api30ResponseBuilderFactory
|
api30ResponseBuilderFactory
|
||||||
.create(formToFill)
|
.create(formToFill)
|
||||||
.fillCredentials(this, request.inlineSuggestionsRequest, callback)
|
.fillCredentials(this, request.inlineSuggestionsRequest, callback)
|
||||||
|
|
|
@ -66,7 +66,7 @@ class PasswordExportService : Service() {
|
||||||
logcat { "Copying ${repositoryDirectory.path} to $targetDirectory" }
|
logcat { "Copying ${repositoryDirectory.path} to $targetDirectory" }
|
||||||
|
|
||||||
val dateString =
|
val dateString =
|
||||||
if (Build.VERSION.SDK_INT >= 26) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME)
|
LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME)
|
||||||
} else {
|
} else {
|
||||||
String.format("%tFT%<tRZ", Calendar.getInstance(TimeZone.getTimeZone("Z")))
|
String.format("%tFT%<tRZ", Calendar.getInstance(TimeZone.getTimeZone("Z")))
|
||||||
|
@ -136,7 +136,7 @@ class PasswordExportService : Service() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createNotificationChannel() {
|
private fun createNotificationChannel() {
|
||||||
if (Build.VERSION.SDK_INT >= 26) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val serviceChannel =
|
val serviceChannel =
|
||||||
NotificationChannel(
|
NotificationChannel(
|
||||||
CHANNEL_ID,
|
CHANNEL_ID,
|
||||||
|
|
|
@ -42,7 +42,7 @@ constructor(
|
||||||
* [MAX_SHORTCUT_COUNT] and older items are removed by a simple LRU sweep.
|
* [MAX_SHORTCUT_COUNT] and older items are removed by a simple LRU sweep.
|
||||||
*/
|
*/
|
||||||
fun addDynamicShortcut(item: PasswordItem, intent: Intent) {
|
fun addDynamicShortcut(item: PasswordItem, intent: Intent) {
|
||||||
if (Build.VERSION.SDK_INT < 25) return
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) return
|
||||||
val shortcutManager: ShortcutManager = context.getSystemService() ?: return
|
val shortcutManager: ShortcutManager = context.getSystemService() ?: return
|
||||||
val shortcut = buildShortcut(item, intent)
|
val shortcut = buildShortcut(item, intent)
|
||||||
val shortcuts = shortcutManager.dynamicShortcuts
|
val shortcuts = shortcutManager.dynamicShortcuts
|
||||||
|
@ -67,7 +67,7 @@ constructor(
|
||||||
* a no-op if the user's default launcher does not support pinned shortcuts.
|
* a no-op if the user's default launcher does not support pinned shortcuts.
|
||||||
*/
|
*/
|
||||||
fun addPinnedShortcut(item: PasswordItem, intent: Intent) {
|
fun addPinnedShortcut(item: PasswordItem, intent: Intent) {
|
||||||
if (Build.VERSION.SDK_INT < 26) return
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
||||||
val shortcutManager: ShortcutManager = context.getSystemService() ?: return
|
val shortcutManager: ShortcutManager = context.getSystemService() ?: return
|
||||||
if (!shortcutManager.isRequestPinShortcutSupported) {
|
if (!shortcutManager.isRequestPinShortcutSupported) {
|
||||||
logcat { "addPinnedShortcut: pin shortcuts unsupported" }
|
logcat { "addPinnedShortcut: pin shortcuts unsupported" }
|
||||||
|
@ -78,7 +78,7 @@ constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a [ShortcutInfo] from [item] and assigns [intent] to it. */
|
/** Creates a [ShortcutInfo] from [item] and assigns [intent] to it. */
|
||||||
@RequiresApi(25)
|
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||||
private fun buildShortcut(item: PasswordItem, intent: Intent): ShortcutInfo {
|
private fun buildShortcut(item: PasswordItem, intent: Intent): ShortcutInfo {
|
||||||
return ShortcutInfo.Builder(context, item.fullPathToParent)
|
return ShortcutInfo.Builder(context, item.fullPathToParent)
|
||||||
.setShortLabel(item.toString())
|
.setShortLabel(item.toString())
|
||||||
|
@ -93,7 +93,7 @@ constructor(
|
||||||
* data, which ensures that the get/set dance in [addDynamicShortcut] does not cause invalidation
|
* 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.
|
* of icon assets, resulting in invisible icons in all but the newest launcher shortcut.
|
||||||
*/
|
*/
|
||||||
@RequiresApi(25)
|
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||||
private fun rebuildShortcut(shortcut: ShortcutInfo): ShortcutInfo {
|
private fun rebuildShortcut(shortcut: ShortcutInfo): ShortcutInfo {
|
||||||
// Non-null assertions are fine since we know these values aren't null.
|
// Non-null assertions are fine since we know these values aren't null.
|
||||||
return ShortcutInfo.Builder(context, shortcut.id)
|
return ShortcutInfo.Builder(context, shortcut.id)
|
||||||
|
|
|
@ -52,7 +52,7 @@ suspend fun <T> Task<T>.suspendableAwait() =
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
class AutofillSmsActivity : AppCompatActivity() {
|
class AutofillSmsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -69,7 +69,7 @@ public sealed class FormOrigin(public open val identifier: String) {
|
||||||
/**
|
/**
|
||||||
* Manages the detection of fields to fill in an [AssistStructure] and determines the [FormOrigin].
|
* Manages the detection of fields to fill in an [AssistStructure] and determines the [FormOrigin].
|
||||||
*/
|
*/
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
private class AutofillFormParser(
|
private class AutofillFormParser(
|
||||||
context: Context,
|
context: Context,
|
||||||
structure: AssistStructure,
|
structure: AssistStructure,
|
||||||
|
@ -200,7 +200,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
|
* 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.
|
* entry point to all fill and save features.
|
||||||
*/
|
*/
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
public class FillableForm
|
public class FillableForm
|
||||||
private constructor(
|
private constructor(
|
||||||
public val formOrigin: FormOrigin,
|
public val formOrigin: FormOrigin,
|
||||||
|
|
|
@ -52,7 +52,7 @@ public fun computeCertificatesHash(context: Context, appPackage: String): String
|
||||||
val signaturesOld =
|
val signaturesOld =
|
||||||
context.packageManager.getPackageInfo(appPackage, PackageManager.GET_SIGNATURES).signatures
|
context.packageManager.getPackageInfo(appPackage, PackageManager.GET_SIGNATURES).signatures
|
||||||
val stableHashOld = stableHash(signaturesOld.map { it.toByteArray() })
|
val stableHashOld = stableHash(signaturesOld.map { it.toByteArray() })
|
||||||
if (Build.VERSION.SDK_INT >= 28) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
val info =
|
val info =
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
context.packageManager.getPackageInfo(
|
context.packageManager.getPackageInfo(
|
||||||
|
@ -79,14 +79,15 @@ public fun computeCertificatesHash(context: Context, appPackage: String): String
|
||||||
* its `webDomain` and `webScheme`, if available.
|
* its `webDomain` and `webScheme`, if available.
|
||||||
*/
|
*/
|
||||||
internal val AssistStructure.ViewNode.webOrigin: String?
|
internal val AssistStructure.ViewNode.webOrigin: String?
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
get() =
|
get() =
|
||||||
webDomain?.let { domain ->
|
webDomain?.let { domain ->
|
||||||
val scheme = (if (Build.VERSION.SDK_INT >= 28) webScheme else null) ?: "https"
|
val scheme =
|
||||||
|
(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) webScheme else null) ?: "https"
|
||||||
"$scheme://$domain"
|
"$scheme://$domain"
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
public class FixedSaveCallback(context: Context, private val callback: SaveCallback) {
|
public class FixedSaveCallback(context: Context, private val callback: SaveCallback) {
|
||||||
|
|
||||||
private val applicationContext = context.applicationContext
|
private val applicationContext = context.applicationContext
|
||||||
|
@ -102,7 +103,7 @@ public class FixedSaveCallback(context: Context, private val callback: SaveCallb
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun onSuccess(intentSender: IntentSender) {
|
public fun onSuccess(intentSender: IntentSender) {
|
||||||
if (Build.VERSION.SDK_INT >= 28) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
callback.onSuccess(intentSender)
|
callback.onSuccess(intentSender)
|
||||||
} else {
|
} else {
|
||||||
callback.onSuccess()
|
callback.onSuccess()
|
||||||
|
@ -129,7 +130,7 @@ private fun visitViewNode(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
internal fun AssistStructure.findNodeByAutofillId(
|
internal fun AssistStructure.findNodeByAutofillId(
|
||||||
autofillId: AutofillId
|
autofillId: AutofillId
|
||||||
): AssistStructure.ViewNode? {
|
): AssistStructure.ViewNode? {
|
||||||
|
|
|
@ -30,7 +30,7 @@ public enum class AutofillAction {
|
||||||
* [FormField], [AssistStructure.ViewNode] or [AutofillId], depending on how much metadata about the
|
* [FormField], [AssistStructure.ViewNode] or [AutofillId], depending on how much metadata about the
|
||||||
* field is needed and available in the particular situation.
|
* field is needed and available in the particular situation.
|
||||||
*/
|
*/
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
public sealed class AutofillScenario<out T : Any> {
|
public sealed class AutofillScenario<out T : Any> {
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
|
@ -185,7 +185,7 @@ public sealed class AutofillScenario<out T : Any> {
|
||||||
get() = username != null
|
get() = username != null
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
internal data class ClassifiedAutofillScenario<T : Any>(
|
internal data class ClassifiedAutofillScenario<T : Any>(
|
||||||
override val username: T?,
|
override val username: T?,
|
||||||
override val fillUsername: Boolean,
|
override val fillUsername: Boolean,
|
||||||
|
@ -206,7 +206,7 @@ internal data class ClassifiedAutofillScenario<T : Any>(
|
||||||
get() = newPassword.ifEmpty { currentPassword }
|
get() = newPassword.ifEmpty { currentPassword }
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
internal data class GenericAutofillScenario<T : Any>(
|
internal data class GenericAutofillScenario<T : Any>(
|
||||||
override val username: T?,
|
override val username: T?,
|
||||||
override val fillUsername: Boolean,
|
override val fillUsername: Boolean,
|
||||||
|
@ -226,7 +226,7 @@ internal data class GenericAutofillScenario<T : Any>(
|
||||||
get() = genericPassword
|
get() = genericPassword
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
internal fun AutofillScenario<FormField>.passesOriginCheck(singleOriginMode: Boolean): Boolean {
|
internal fun AutofillScenario<FormField>.passesOriginCheck(singleOriginMode: Boolean): Boolean {
|
||||||
return if (singleOriginMode) {
|
return if (singleOriginMode) {
|
||||||
// In single origin mode, only the browsers URL bar (which is never filled) should have
|
// In single origin mode, only the browsers URL bar (which is never filled) should have
|
||||||
|
@ -239,7 +239,7 @@ internal fun AutofillScenario<FormField>.passesOriginCheck(singleOriginMode: Boo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
@JvmName("fillWithAutofillId")
|
@JvmName("fillWithAutofillId")
|
||||||
public fun Dataset.Builder.fillWith(
|
public fun Dataset.Builder.fillWith(
|
||||||
scenario: AutofillScenario<AutofillId>,
|
scenario: AutofillScenario<AutofillId>,
|
||||||
|
@ -262,7 +262,7 @@ public fun Dataset.Builder.fillWith(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
internal inline fun <T : Any, S : Any> AutofillScenario<T>.map(
|
internal inline fun <T : Any, S : Any> AutofillScenario<T>.map(
|
||||||
transform: (T) -> S
|
transform: (T) -> S
|
||||||
): AutofillScenario<S> {
|
): AutofillScenario<S> {
|
||||||
|
@ -282,7 +282,7 @@ internal inline fun <T : Any, S : Any> AutofillScenario<T>.map(
|
||||||
return builder.build()
|
return builder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
@JvmName("toBundleAutofillId")
|
@JvmName("toBundleAutofillId")
|
||||||
internal fun AutofillScenario<AutofillId>.toBundle(): Bundle =
|
internal fun AutofillScenario<AutofillId>.toBundle(): Bundle =
|
||||||
when (this) {
|
when (this) {
|
||||||
|
@ -311,7 +311,7 @@ internal fun AutofillScenario<AutofillId>.toBundle(): Bundle =
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
public fun AutofillScenario<AutofillId>.recoverNodes(
|
public fun AutofillScenario<AutofillId>.recoverNodes(
|
||||||
structure: AssistStructure
|
structure: AssistStructure
|
||||||
): AutofillScenario<AssistStructure.ViewNode>? {
|
): AutofillScenario<AssistStructure.ViewNode>? {
|
||||||
|
@ -319,13 +319,13 @@ public fun AutofillScenario<AutofillId>.recoverNodes(
|
||||||
}
|
}
|
||||||
|
|
||||||
public val AutofillScenario<AssistStructure.ViewNode>.usernameValue: String?
|
public val AutofillScenario<AssistStructure.ViewNode>.usernameValue: String?
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
get() {
|
get() {
|
||||||
val value = username?.autofillValue ?: return null
|
val value = username?.autofillValue ?: return null
|
||||||
return if (value.isText) value.textValue.toString() else null
|
return if (value.isText) value.textValue.toString() else null
|
||||||
}
|
}
|
||||||
public val AutofillScenario<AssistStructure.ViewNode>.passwordValue: String?
|
public val AutofillScenario<AssistStructure.ViewNode>.passwordValue: String?
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
get() {
|
get() {
|
||||||
val distinctValues =
|
val distinctValues =
|
||||||
passwordFieldsToSave
|
passwordFieldsToSave
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
*/
|
*/
|
||||||
package com.github.androidpasswordstore.autofillparser
|
package com.github.androidpasswordstore.autofillparser
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import com.github.androidpasswordstore.autofillparser.CertaintyLevel.Certain
|
import com.github.androidpasswordstore.autofillparser.CertaintyLevel.Certain
|
||||||
import com.github.androidpasswordstore.autofillparser.CertaintyLevel.Likely
|
import com.github.androidpasswordstore.autofillparser.CertaintyLevel.Likely
|
||||||
|
@ -21,7 +22,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
|
* The strategy used to detect [AutofillScenario] s; expressed using the DSL implemented in
|
||||||
* [AutofillDsl].
|
* [AutofillDsl].
|
||||||
*/
|
*/
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
internal val autofillStrategy = strategy {
|
internal val autofillStrategy = strategy {
|
||||||
|
|
||||||
// Match two new password fields, an optional current password field right below or above, and
|
// Match two new password fields, an optional current password field right below or above, and
|
||||||
|
|
|
@ -4,13 +4,14 @@
|
||||||
*/
|
*/
|
||||||
package com.github.androidpasswordstore.autofillparser
|
package com.github.androidpasswordstore.autofillparser
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import logcat.LogPriority.WARN
|
import logcat.LogPriority.WARN
|
||||||
import logcat.logcat
|
import logcat.logcat
|
||||||
|
|
||||||
@DslMarker internal annotation class AutofillDsl
|
@DslMarker internal annotation class AutofillDsl
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
internal interface FieldMatcher {
|
internal interface FieldMatcher {
|
||||||
|
|
||||||
fun match(fields: List<FormField>, alreadyMatched: List<FormField>): List<FormField>?
|
fun match(fields: List<FormField>, alreadyMatched: List<FormField>): List<FormField>?
|
||||||
|
@ -71,7 +72,7 @@ internal interface FieldMatcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
internal class SingleFieldMatcher(
|
internal class SingleFieldMatcher(
|
||||||
private val take: (FormField, List<FormField>) -> Boolean,
|
private val take: (FormField, List<FormField>) -> Boolean,
|
||||||
private val tieBreakers: List<(FormField, List<FormField>) -> Boolean>
|
private val tieBreakers: List<(FormField, List<FormField>) -> Boolean>
|
||||||
|
@ -135,7 +136,7 @@ internal class SingleFieldMatcher(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
private class PairOfFieldsMatcher(
|
private class PairOfFieldsMatcher(
|
||||||
private val take: (Pair<FormField, FormField>, List<FormField>) -> Boolean,
|
private val take: (Pair<FormField, FormField>, List<FormField>) -> Boolean,
|
||||||
private val tieBreakers: List<(Pair<FormField, FormField>, List<FormField>) -> Boolean>
|
private val tieBreakers: List<(Pair<FormField, FormField>, List<FormField>) -> Boolean>
|
||||||
|
@ -173,7 +174,7 @@ private class PairOfFieldsMatcher(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
internal class AutofillRule
|
internal class AutofillRule
|
||||||
private constructor(
|
private constructor(
|
||||||
private val matchers: List<AutofillRuleMatcher>,
|
private val matchers: List<AutofillRuleMatcher>,
|
||||||
|
@ -381,7 +382,7 @@ private constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
internal class AutofillStrategy private constructor(private val rules: List<AutofillRule>) {
|
internal class AutofillStrategy private constructor(private val rules: List<AutofillRule>) {
|
||||||
|
|
||||||
@AutofillDsl
|
@AutofillDsl
|
||||||
|
@ -434,6 +435,6 @@ internal class AutofillStrategy private constructor(private val rules: List<Auto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
internal fun strategy(block: AutofillStrategy.Builder.() -> Unit) =
|
internal fun strategy(block: AutofillStrategy.Builder.() -> Unit) =
|
||||||
AutofillStrategy.Builder().apply(block).build()
|
AutofillStrategy.Builder().apply(block).build()
|
||||||
|
|
|
@ -143,7 +143,7 @@ private fun getBrowserMultiOriginMethod(appPackage: String): BrowserMultiOriginM
|
||||||
* Some browsers may not issue save requests automatically and thus need
|
* Some browsers may not issue save requests automatically and thus need
|
||||||
* `FLAG_SAVE_ON_ALL_VIEW_INVISIBLE` to be set.
|
* `FLAG_SAVE_ON_ALL_VIEW_INVISIBLE` to be set.
|
||||||
*/
|
*/
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
private val BROWSER_SAVE_FLAG =
|
private val BROWSER_SAVE_FLAG =
|
||||||
mapOf(
|
mapOf(
|
||||||
"com.duckduckgo.mobile.android" to 0,
|
"com.duckduckgo.mobile.android" to 0,
|
||||||
|
@ -157,7 +157,7 @@ private val BROWSER_SAVE_FLAG =
|
||||||
"com.opera.touch" to 0,
|
"com.opera.touch" to 0,
|
||||||
)
|
)
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
private val BROWSER_SAVE_FLAG_IF_NO_ACCESSIBILITY =
|
private val BROWSER_SAVE_FLAG_IF_NO_ACCESSIBILITY =
|
||||||
mapOf(
|
mapOf(
|
||||||
"com.android.chrome" to SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE,
|
"com.android.chrome" to SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE,
|
||||||
|
@ -177,7 +177,7 @@ private fun isNoAccessibilityServiceEnabled(context: Context): Boolean {
|
||||||
.isNullOrEmpty()
|
.isNullOrEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
private fun getBrowserSaveFlag(context: Context, appPackage: String): Int? =
|
private fun getBrowserSaveFlag(context: Context, appPackage: String): Int? =
|
||||||
BROWSER_SAVE_FLAG[appPackage]
|
BROWSER_SAVE_FLAG[appPackage]
|
||||||
?: BROWSER_SAVE_FLAG_IF_NO_ACCESSIBILITY[appPackage]?.takeIf {
|
?: BROWSER_SAVE_FLAG_IF_NO_ACCESSIBILITY[appPackage]?.takeIf {
|
||||||
|
@ -189,7 +189,7 @@ internal data class BrowserAutofillSupportInfo(
|
||||||
val saveFlags: Int?
|
val saveFlags: Int?
|
||||||
)
|
)
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
internal fun getBrowserAutofillSupportInfoIfTrusted(
|
internal fun getBrowserAutofillSupportInfoIfTrusted(
|
||||||
context: Context,
|
context: Context,
|
||||||
appPackage: String
|
appPackage: String
|
||||||
|
@ -215,7 +215,7 @@ public enum class BrowserAutofillSupportLevel {
|
||||||
GeneralFillAndSave,
|
GeneralFillAndSave,
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
private fun getBrowserAutofillSupportLevel(
|
private fun getBrowserAutofillSupportLevel(
|
||||||
context: Context,
|
context: Context,
|
||||||
appPackage: String
|
appPackage: String
|
||||||
|
@ -237,12 +237,13 @@ private fun getBrowserAutofillSupportLevel(
|
||||||
// browsers
|
// browsers
|
||||||
// with native Autofill support offer full save support as well, we reuse the list of those
|
// with native Autofill support offer full save support as well, we reuse the list of those
|
||||||
// browsers here.
|
// browsers here.
|
||||||
supportLevel != BrowserAutofillSupportLevel.GeneralFillAndSave && Build.VERSION.SDK_INT < 28
|
supportLevel != BrowserAutofillSupportLevel.GeneralFillAndSave &&
|
||||||
|
Build.VERSION.SDK_INT < Build.VERSION_CODES.P
|
||||||
}
|
}
|
||||||
?: BrowserAutofillSupportLevel.None
|
?: BrowserAutofillSupportLevel.None
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
public fun getInstalledBrowsersWithAutofillSupportLevel(
|
public fun getInstalledBrowsersWithAutofillSupportLevel(
|
||||||
context: Context
|
context: Context
|
||||||
): List<Pair<String, BrowserAutofillSupportLevel>> {
|
): List<Pair<String, BrowserAutofillSupportLevel>> {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package com.github.androidpasswordstore.autofillparser
|
package com.github.androidpasswordstore.autofillparser
|
||||||
|
|
||||||
import android.app.assist.AssistStructure
|
import android.app.assist.AssistStructure
|
||||||
|
import android.os.Build
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.autofill.AutofillId
|
import android.view.autofill.AutofillId
|
||||||
|
@ -23,7 +24,7 @@ internal enum class CertaintyLevel {
|
||||||
* Represents a single potentially fillable or saveable field together with all meta data extracted
|
* Represents a single potentially fillable or saveable field together with all meta data extracted
|
||||||
* from its [AssistStructure.ViewNode].
|
* from its [AssistStructure.ViewNode].
|
||||||
*/
|
*/
|
||||||
@RequiresApi(26)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
internal class FormField(
|
internal class FormField(
|
||||||
node: AssistStructure.ViewNode,
|
node: AssistStructure.ViewNode,
|
||||||
private val index: Int,
|
private val index: Int,
|
||||||
|
@ -113,7 +114,8 @@ internal class FormField(
|
||||||
.toSet()
|
.toSet()
|
||||||
.toList()
|
.toList()
|
||||||
|
|
||||||
@RequiresApi(26) private fun isSupportedHint(hint: String?) = hint in HINTS_FILLABLE
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
private fun isSupportedHint(hint: String?) = hint in HINTS_FILLABLE
|
||||||
private val EXCLUDED_TERMS =
|
private val EXCLUDED_TERMS =
|
||||||
listOf(
|
listOf(
|
||||||
"url_bar", // Chrome/Edge/Firefox address bar
|
"url_bar", // Chrome/Edge/Firefox address bar
|
||||||
|
|
|
@ -53,7 +53,7 @@ internal fun getPublicSuffixPlusOne(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isNumericAddress(domain: String): Boolean {
|
private fun isNumericAddress(domain: String): Boolean {
|
||||||
return if (Build.VERSION.SDK_INT >= 29) {
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
InetAddresses.isNumericAddress(domain)
|
InetAddresses.isNumericAddress(domain)
|
||||||
} else {
|
} else {
|
||||||
@Suppress("DEPRECATION") Patterns.IP_ADDRESS.matcher(domain).matches()
|
@Suppress("DEPRECATION") Patterns.IP_ADDRESS.matcher(domain).matches()
|
||||||
|
|
|
@ -22,8 +22,9 @@ public suspend inline fun <V> runSuspendCatching(block: () -> V): Result<V, Thro
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
Ok(block())
|
Ok(block())
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
throw e
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
if (e is CancellationException) throw e
|
|
||||||
Err(e)
|
Err(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,8 +43,9 @@ public suspend inline infix fun <T, V> T.runSuspendCatching(
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
Ok(block())
|
Ok(block())
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
throw e
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
if (e is CancellationException) throw e
|
|
||||||
Err(e)
|
Err(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,59 +35,28 @@
|
||||||
<ID>LongMethod:RepositorySettings.kt$RepositorySettings$override fun provideSettings(builder: PreferenceScreen.Builder)</ID>
|
<ID>LongMethod:RepositorySettings.kt$RepositorySettings$override fun provideSettings(builder: PreferenceScreen.Builder)</ID>
|
||||||
<ID>LoopWithTooManyJumpStatements:AutofillMatcher.kt$AutofillMatcher.Companion$for ((key, value) in prefs.all) { if (!key.startsWith(PREFERENCE_PREFIX_MATCHES)) continue // We know that preferences starting with `PREFERENCE_PREFIX_MATCHES` were // created with `putStringSet`. @Suppress("UNCHECKED_CAST") val oldMatches = value as? Set<String> if (oldMatches == null) { logcat(WARN) { "Failed to read matches for $key" } continue } // Delete all matches for file locations that are going to be overwritten, then // transfer matches over to the files at their new locations. val newMatches = oldMatches .asSequence() .minus(deletePathList) .minus(oldNewPathMap.values) .map { match -> val newPath = oldNewPathMap[match] ?: return@map match logcat { "Updating match for $key: $match --> $newPath" } newPath } .toSet() if (newMatches != oldMatches) prefs.edit { putStringSet(key, newMatches) } }</ID>
|
<ID>LoopWithTooManyJumpStatements:AutofillMatcher.kt$AutofillMatcher.Companion$for ((key, value) in prefs.all) { if (!key.startsWith(PREFERENCE_PREFIX_MATCHES)) continue // We know that preferences starting with `PREFERENCE_PREFIX_MATCHES` were // created with `putStringSet`. @Suppress("UNCHECKED_CAST") val oldMatches = value as? Set<String> if (oldMatches == null) { logcat(WARN) { "Failed to read matches for $key" } continue } // Delete all matches for file locations that are going to be overwritten, then // transfer matches over to the files at their new locations. val newMatches = oldMatches .asSequence() .minus(deletePathList) .minus(oldNewPathMap.values) .map { match -> val newPath = oldNewPathMap[match] ?: return@map match logcat { "Updating match for $key: $match --> $newPath" } newPath } .toSet() if (newMatches != oldMatches) prefs.edit { putStringSet(key, newMatches) } }</ID>
|
||||||
<ID>LoopWithTooManyJumpStatements:ErrorMessages.kt$ErrorMessages$while (cause.cause != null) { if (cause is GitException) break val nextCause = cause.cause!! if (nextCause is RemoteException) break cause = nextCause }</ID>
|
<ID>LoopWithTooManyJumpStatements:ErrorMessages.kt$ErrorMessages$while (cause.cause != null) { if (cause is GitException) break val nextCause = cause.cause!! if (nextCause is RemoteException) break cause = nextCause }</ID>
|
||||||
<ID>MagicNumber:Api30AutofillResponseBuilder.kt$Api30AutofillResponseBuilder$30</ID>
|
|
||||||
<ID>MagicNumber:AutofillDecryptActivity.kt$AutofillDecryptActivity$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillDecryptActivity.kt$AutofillDecryptActivity.Companion$31</ID>
|
|
||||||
<ID>MagicNumber:AutofillFilterView.kt$AutofillFilterView$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillFilterView.kt$AutofillFilterView.Companion$31</ID>
|
|
||||||
<ID>MagicNumber:AutofillPreferences.kt$DirectoryStructure$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillPublisherChangedActivity.kt$AutofillPublisherChangedActivity$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillPublisherChangedActivity.kt$AutofillPublisherChangedActivity.Companion$31</ID>
|
|
||||||
<ID>MagicNumber:AutofillResponseBuilder.kt$AutofillResponseBuilder$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillResponseBuilder.kt$AutofillResponseBuilder$28</ID>
|
|
||||||
<ID>MagicNumber:AutofillResponseBuilder.kt$AutofillResponseBuilder.Companion$28</ID>
|
|
||||||
<ID>MagicNumber:AutofillSaveActivity.kt$AutofillSaveActivity$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillSettings.kt$AutofillSettings$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillViewUtils.kt$30</ID>
|
|
||||||
<ID>MagicNumber:AutofillViewUtils.kt$31</ID>
|
|
||||||
<ID>MagicNumber:BasePgpActivity.kt$BasePgpActivity$26</ID>
|
|
||||||
<ID>MagicNumber:BasePgpActivity.kt$BasePgpActivity$45</ID>
|
<ID>MagicNumber:BasePgpActivity.kt$BasePgpActivity$45</ID>
|
||||||
<ID>MagicNumber:ClipboardService.kt$ClipboardService$1000</ID>
|
<ID>MagicNumber:ClipboardService.kt$ClipboardService$1000</ID>
|
||||||
<ID>MagicNumber:ClipboardService.kt$ClipboardService$1000L</ID>
|
<ID>MagicNumber:ClipboardService.kt$ClipboardService$1000L</ID>
|
||||||
<ID>MagicNumber:ClipboardService.kt$ClipboardService$23</ID>
|
|
||||||
<ID>MagicNumber:ClipboardService.kt$ClipboardService$24</ID>
|
|
||||||
<ID>MagicNumber:ClipboardService.kt$ClipboardService$26</ID>
|
|
||||||
<ID>MagicNumber:ClipboardService.kt$ClipboardService$31</ID>
|
|
||||||
<ID>MagicNumber:ClipboardService.kt$ClipboardService$45</ID>
|
<ID>MagicNumber:ClipboardService.kt$ClipboardService$45</ID>
|
||||||
<ID>MagicNumber:ClipboardService.kt$ClipboardService$500</ID>
|
<ID>MagicNumber:ClipboardService.kt$ClipboardService$500</ID>
|
||||||
<ID>MagicNumber:DicewareModule.kt$DicewareModule$6</ID>
|
<ID>MagicNumber:DicewareModule.kt$DicewareModule$6</ID>
|
||||||
<ID>MagicNumber:DicewarePasswordGeneratorDialogFragment.kt$DicewarePasswordGeneratorDialogFragment$5</ID>
|
<ID>MagicNumber:DicewarePasswordGeneratorDialogFragment.kt$DicewarePasswordGeneratorDialogFragment$5</ID>
|
||||||
<ID>MagicNumber:Extensions.kt$1000</ID>
|
<ID>MagicNumber:Extensions.kt$1000</ID>
|
||||||
<ID>MagicNumber:GeneralSettings.kt$GeneralSettings$25</ID>
|
|
||||||
<ID>MagicNumber:GitConfigActivity.kt$GitConfigActivity$0.5f</ID>
|
<ID>MagicNumber:GitConfigActivity.kt$GitConfigActivity$0.5f</ID>
|
||||||
<ID>MagicNumber:GitConfigActivity.kt$GitConfigActivity$500</ID>
|
<ID>MagicNumber:GitConfigActivity.kt$GitConfigActivity$500</ID>
|
||||||
<ID>MagicNumber:GitConfigActivity.kt$GitConfigActivity$8</ID>
|
<ID>MagicNumber:GitConfigActivity.kt$GitConfigActivity$8</ID>
|
||||||
<ID>MagicNumber:GitLogAdapter.kt$8</ID>
|
<ID>MagicNumber:GitLogAdapter.kt$8</ID>
|
||||||
<ID>MagicNumber:GitServerConfigActivity.kt$GitServerConfigActivity$500</ID>
|
<ID>MagicNumber:GitServerConfigActivity.kt$GitServerConfigActivity$500</ID>
|
||||||
<ID>MagicNumber:LaunchActivity.kt$LaunchActivity$500L</ID>
|
<ID>MagicNumber:LaunchActivity.kt$LaunchActivity$500L</ID>
|
||||||
<ID>MagicNumber:OreoAutofillService.kt$OreoAutofillService$26</ID>
|
|
||||||
<ID>MagicNumber:OreoAutofillService.kt$OreoAutofillService$28</ID>
|
|
||||||
<ID>MagicNumber:OreoAutofillService.kt$OreoAutofillService$30</ID>
|
|
||||||
<ID>MagicNumber:PasswordCreationActivity.kt$PasswordCreationActivity$28</ID>
|
|
||||||
<ID>MagicNumber:PasswordExportService.kt$PasswordExportService$1024</ID>
|
<ID>MagicNumber:PasswordExportService.kt$PasswordExportService$1024</ID>
|
||||||
<ID>MagicNumber:PasswordExportService.kt$PasswordExportService$26</ID>
|
|
||||||
<ID>MagicNumber:PasswordGeneratorDialogFragment.kt$PasswordGeneratorDialogFragment$20</ID>
|
<ID>MagicNumber:PasswordGeneratorDialogFragment.kt$PasswordGeneratorDialogFragment$20</ID>
|
||||||
<ID>MagicNumber:PasswordItemRecyclerAdapter.kt$PasswordItemRecyclerAdapter.PasswordItemViewHolder$0.7f</ID>
|
<ID>MagicNumber:PasswordItemRecyclerAdapter.kt$PasswordItemRecyclerAdapter.PasswordItemViewHolder$0.7f</ID>
|
||||||
<ID>MagicNumber:ProxySelectorActivity.kt$ProxySelectorActivity$29</ID>
|
|
||||||
<ID>MagicNumber:ProxySelectorActivity.kt$ProxySelectorActivity$500</ID>
|
<ID>MagicNumber:ProxySelectorActivity.kt$ProxySelectorActivity$500</ID>
|
||||||
<ID>MagicNumber:RepositorySettings.kt$RepositorySettings$25</ID>
|
|
||||||
<ID>MagicNumber:ShortcutHandler.kt$ShortcutHandler$25</ID>
|
|
||||||
<ID>MagicNumber:ShortcutHandler.kt$ShortcutHandler$26</ID>
|
|
||||||
<ID>MagicNumber:SshKey.kt$SshKey$100_000</ID>
|
<ID>MagicNumber:SshKey.kt$SshKey$100_000</ID>
|
||||||
<ID>MagicNumber:SshKey.kt$SshKey$15</ID>
|
<ID>MagicNumber:SshKey.kt$SshKey$15</ID>
|
||||||
<ID>MagicNumber:SshKey.kt$SshKey$30</ID>
|
<ID>MagicNumber:SshKey.kt$SshKey$30</ID>
|
||||||
<ID>MagicNumber:SshKey.kt$SshKey.Algorithm.Ecdsa$256</ID>
|
<ID>MagicNumber:SshKey.kt$SshKey.Algorithm.Ecdsa$256</ID>
|
||||||
<ID>MagicNumber:SshKey.kt$SshKey.Algorithm.Ecdsa$28</ID>
|
|
||||||
<ID>MagicNumber:SshKey.kt$SshKey.Algorithm.Rsa$3072</ID>
|
<ID>MagicNumber:SshKey.kt$SshKey.Algorithm.Rsa$3072</ID>
|
||||||
<ID>MagicNumber:SshjSessionFactory.kt$SshjSession$22</ID>
|
<ID>MagicNumber:SshjSessionFactory.kt$SshjSession$22</ID>
|
||||||
<ID>MagicNumber:UriTotpFinder.kt$UriTotpFinder$30</ID>
|
<ID>MagicNumber:UriTotpFinder.kt$UriTotpFinder$30</ID>
|
||||||
|
@ -124,9 +93,7 @@
|
||||||
<ID>ThrowsCount:GitCommandExecutor.kt$GitCommandExecutor$suspend fun execute(): Result<Unit, Throwable></ID>
|
<ID>ThrowsCount:GitCommandExecutor.kt$GitCommandExecutor$suspend fun execute(): Result<Unit, Throwable></ID>
|
||||||
<ID>ThrowsCount:SshKey.kt$SshKey$fun import(uri: Uri)</ID>
|
<ID>ThrowsCount:SshKey.kt$SshKey$fun import(uri: Uri)</ID>
|
||||||
<ID>TooManyFunctions:PasswordStore.kt$PasswordStore : BaseGitActivity</ID>
|
<ID>TooManyFunctions:PasswordStore.kt$PasswordStore : BaseGitActivity</ID>
|
||||||
<ID>TooManyFunctions:SearchableRepositoryViewModel.kt$SearchableRepositoryViewModel : AndroidViewModel</ID>
|
|
||||||
<ID>TooManyFunctions:SshjConfig.kt$AbstractLogger : Logger</ID>
|
<ID>TooManyFunctions:SshjConfig.kt$AbstractLogger : Logger</ID>
|
||||||
<ID>TooManyFunctions:SshjConfig.kt$LogcatLoggerFactory$LogcatLogger : AbstractLogger</ID>
|
|
||||||
<ID>TopLevelPropertyNaming:AutofillMatcher.kt$private const val PREFERENCES_AUTOFILL_APP_MATCHES = "oreo_autofill_app_matches"</ID>
|
<ID>TopLevelPropertyNaming:AutofillMatcher.kt$private const val PREFERENCES_AUTOFILL_APP_MATCHES = "oreo_autofill_app_matches"</ID>
|
||||||
<ID>TopLevelPropertyNaming:AutofillMatcher.kt$private const val PREFERENCES_AUTOFILL_WEB_MATCHES = "oreo_autofill_web_matches"</ID>
|
<ID>TopLevelPropertyNaming:AutofillMatcher.kt$private const val PREFERENCES_AUTOFILL_WEB_MATCHES = "oreo_autofill_web_matches"</ID>
|
||||||
<ID>TopLevelPropertyNaming:Extensions.kt$/** The default OpenPGP provider for the app */ const val OPENPGP_PROVIDER = "org.sufficientlysecure.keychain"</ID>
|
<ID>TopLevelPropertyNaming:Extensions.kt$/** The default OpenPGP provider for the app */ const val OPENPGP_PROVIDER = "org.sufficientlysecure.keychain"</ID>
|
||||||
|
@ -134,8 +101,6 @@
|
||||||
<ID>TopLevelPropertyNaming:SshKey.kt$private const val ANDROIDX_SECURITY_KEYSET_PREF_NAME = "androidx_sshkey_keyset_prefs"</ID>
|
<ID>TopLevelPropertyNaming:SshKey.kt$private const val ANDROIDX_SECURITY_KEYSET_PREF_NAME = "androidx_sshkey_keyset_prefs"</ID>
|
||||||
<ID>TopLevelPropertyNaming:SshKey.kt$private const val KEYSTORE_ALIAS = "sshkey"</ID>
|
<ID>TopLevelPropertyNaming:SshKey.kt$private const val KEYSTORE_ALIAS = "sshkey"</ID>
|
||||||
<ID>TopLevelPropertyNaming:SshKey.kt$private const val PROVIDER_ANDROID_KEY_STORE = "AndroidKeyStore"</ID>
|
<ID>TopLevelPropertyNaming:SshKey.kt$private const val PROVIDER_ANDROID_KEY_STORE = "AndroidKeyStore"</ID>
|
||||||
<ID>UnusedPrivateMember:PasswordStore.kt$PasswordStore$private val directorySelectAction = registerForActivityResult(StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { checkLocalRepository() } }</ID>
|
|
||||||
<ID>UnusedPrivateMember:PasswordStore.kt$PasswordStore$private val storagePermissionRequest = registerForActivityResult(RequestPermission()) { granted -> if (granted) checkLocalRepository() }</ID>
|
|
||||||
<ID>UseCheckOrError:CredentialFinder.kt$CredentialFinder$throw IllegalStateException("Only SshKey and Password connection mode ask for passwords")</ID>
|
<ID>UseCheckOrError:CredentialFinder.kt$CredentialFinder$throw IllegalStateException("Only SshKey and Password connection mode ask for passwords")</ID>
|
||||||
<ID>UseCheckOrError:FragmentViewBindingDelegate.kt$FragmentViewBindingDelegate$throw IllegalStateException( "Should not attempt to get bindings when Fragment views are destroyed." )</ID>
|
<ID>UseCheckOrError:FragmentViewBindingDelegate.kt$FragmentViewBindingDelegate$throw IllegalStateException( "Should not attempt to get bindings when Fragment views are destroyed." )</ID>
|
||||||
<ID>UseCheckOrError:GitOperation.kt$GitOperation$throw IllegalStateException("Biometric authentication failures should be ignored")</ID>
|
<ID>UseCheckOrError:GitOperation.kt$GitOperation$throw IllegalStateException("Biometric authentication failures should be ignored")</ID>
|
||||||
|
|
|
@ -11,30 +11,9 @@
|
||||||
<ID>LoopWithTooManyJumpStatements:AutofillStrategyDsl.kt$PairOfFieldsMatcher$for ((i, tieBreaker) in tieBreakers.withIndex()) { val new = current.filter { tieBreaker(it, alreadyMatched) } if (new.isEmpty()) { logcat { "Tie breaker #${i + 1}: Didn't match any pair of fields; skipping" } continue } // and return if the available options have been narrowed to a single field. if (new.size == 1) { logcat { "Tie breaker #${i + 1}: Success" } current = new break } logcat { "Tie breaker #${i + 1}: Matched ${new.size} pairs of fields; continuing" } current = new }</ID>
|
<ID>LoopWithTooManyJumpStatements:AutofillStrategyDsl.kt$PairOfFieldsMatcher$for ((i, tieBreaker) in tieBreakers.withIndex()) { val new = current.filter { tieBreaker(it, alreadyMatched) } if (new.isEmpty()) { logcat { "Tie breaker #${i + 1}: Didn't match any pair of fields; skipping" } continue } // and return if the available options have been narrowed to a single field. if (new.size == 1) { logcat { "Tie breaker #${i + 1}: Success" } current = new break } logcat { "Tie breaker #${i + 1}: Matched ${new.size} pairs of fields; continuing" } current = new }</ID>
|
||||||
<ID>LoopWithTooManyJumpStatements:AutofillStrategyDsl.kt$SingleFieldMatcher$for ((i, tieBreaker) in tieBreakers.withIndex()) { // Successively filter matched fields via tie breakers... val new = current.filter { tieBreaker(it, alreadyMatched) } // skipping those tie breakers that are not satisfied for any remaining field... if (new.isEmpty()) { logcat { "Tie breaker #${i + 1}: Didn't match any field; skipping" } continue } // and return if the available options have been narrowed to a single field. if (new.size == 1) { logcat { "Tie breaker #${i + 1}: Success" } current = new break } logcat { "Tie breaker #${i + 1}: Matched ${new.size} fields; continuing" } current = new }</ID>
|
<ID>LoopWithTooManyJumpStatements:AutofillStrategyDsl.kt$SingleFieldMatcher$for ((i, tieBreaker) in tieBreakers.withIndex()) { // Successively filter matched fields via tie breakers... val new = current.filter { tieBreaker(it, alreadyMatched) } // skipping those tie breakers that are not satisfied for any remaining field... if (new.isEmpty()) { logcat { "Tie breaker #${i + 1}: Didn't match any field; skipping" } continue } // and return if the available options have been narrowed to a single field. if (new.size == 1) { logcat { "Tie breaker #${i + 1}: Success" } current = new break } logcat { "Tie breaker #${i + 1}: Matched ${new.size} fields; continuing" } current = new }</ID>
|
||||||
<ID>LoopWithTooManyJumpStatements:ByteArray.kt$while (true) { val byte0 = if (expectDot) { expectDot = false '.'.code.toByte() } else { labels[currentLabelIndex][currentLabelByteIndex] and BITMASK } val byte1 = this[start + publicSuffixByteIndex] and BITMASK // Compare the bytes. Note that the file stores UTF-8 encoded bytes, so we must compare // the // unsigned bytes. compareResult = (byte0.toUByte() - byte1.toUByte()).toInt() if (compareResult != 0) { break } publicSuffixByteIndex++ currentLabelByteIndex++ if (publicSuffixByteIndex == publicSuffixLength) { break } if (labels[currentLabelIndex].size == currentLabelByteIndex) { // We've exhausted our current label. Either there are more labels to compare, in // which // case we expect a dot as the next character. Otherwise, we've checked all our // labels. if (currentLabelIndex == labels.size - 1) { break } else { currentLabelIndex++ currentLabelByteIndex = -1 expectDot = true } } }</ID>
|
<ID>LoopWithTooManyJumpStatements:ByteArray.kt$while (true) { val byte0 = if (expectDot) { expectDot = false '.'.code.toByte() } else { labels[currentLabelIndex][currentLabelByteIndex] and BITMASK } val byte1 = this[start + publicSuffixByteIndex] and BITMASK // Compare the bytes. Note that the file stores UTF-8 encoded bytes, so we must compare // the // unsigned bytes. compareResult = (byte0.toUByte() - byte1.toUByte()).toInt() if (compareResult != 0) { break } publicSuffixByteIndex++ currentLabelByteIndex++ if (publicSuffixByteIndex == publicSuffixLength) { break } if (labels[currentLabelIndex].size == currentLabelByteIndex) { // We've exhausted our current label. Either there are more labels to compare, in // which // case we expect a dot as the next character. Otherwise, we've checked all our // labels. if (currentLabelIndex == labels.size - 1) { break } else { currentLabelIndex++ currentLabelByteIndex = -1 expectDot = true } } }</ID>
|
||||||
<ID>MagicNumber:AutofillFormParser.kt$AutofillFormParser$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillFormParser.kt$FillableForm$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillHelper.kt$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillHelper.kt$28</ID>
|
|
||||||
<ID>MagicNumber:AutofillHelper.kt$FixedSaveCallback$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillHelper.kt$FixedSaveCallback$28</ID>
|
|
||||||
<ID>MagicNumber:AutofillHelper.kt$FixedSaveCallback$29</ID>
|
<ID>MagicNumber:AutofillHelper.kt$FixedSaveCallback$29</ID>
|
||||||
<ID>MagicNumber:AutofillScenario.kt$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillScenario.kt$4</ID>
|
<ID>MagicNumber:AutofillScenario.kt$4</ID>
|
||||||
<ID>MagicNumber:AutofillScenario.kt$5</ID>
|
<ID>MagicNumber:AutofillScenario.kt$5</ID>
|
||||||
<ID>MagicNumber:AutofillScenario.kt$AutofillScenario$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillScenario.kt$ClassifiedAutofillScenario$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillScenario.kt$GenericAutofillScenario$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillStrategyDsl.kt$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillStrategyDsl.kt$AutofillRule$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillStrategyDsl.kt$AutofillStrategy$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillStrategyDsl.kt$FieldMatcher$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillStrategyDsl.kt$PairOfFieldsMatcher$26</ID>
|
|
||||||
<ID>MagicNumber:AutofillStrategyDsl.kt$SingleFieldMatcher$26</ID>
|
|
||||||
<ID>MagicNumber:FeatureAndTrustDetection.kt$26</ID>
|
|
||||||
<ID>MagicNumber:FeatureAndTrustDetection.kt$28</ID>
|
|
||||||
<ID>MagicNumber:FormField.kt$FormField$26</ID>
|
|
||||||
<ID>MagicNumber:FormField.kt$FormField.Companion$26</ID>
|
|
||||||
<ID>MagicNumber:PublicSuffixListCache.kt$29</ID>
|
|
||||||
<ID>MaxLineLength:FeatureAndTrustDetection.kt$/* In order to add a new browser, do the following: 1. Obtain the .apk from a trusted source. For example, download it from the Play Store on your phone and use adb pull to get it onto your computer. We will assume that it is called browser.apk. 2. Run aapt dump badging browser.apk | grep package: | grep -Eo " name='[a-zA-Z0-9_\.]*" | cut -c8- to obtain the package name (actually, the application ID) of the app in the .apk. 3. Run apksigner verify --print-certs browser.apk | grep "#1 certificate SHA-256" | grep -Eo "[a-f0-9]{64}" | tr -d '\n' | xxd -r -p | base64 to calculate the hash of browser.apk's first signing certificate. Note: This will only work if the apk has a single signing certificate. Apps with multiple signers are very rare, so there is probably no need to add them. Refer to computeCertificatesHash to learn how the hash would be computed in this case. 4. Verify the package name and the hash, for example by asking other people to repeat the steps above. 5. Add an entry with the browser apps's package name and the hash to TRUSTED_BROWSER_CERTIFICATE_HASH. 6. Optionally, try adding the browser's package name to BROWSERS_WITH_SAVE_SUPPORT and check whether a save request to Password Store is triggered when you submit a registration form. 7. Optionally, try adding the browser's package name to BROWSERS_WITH_MULTI_ORIGIN_SUPPORT and check whether it correctly distinguishes web origins even if iframes are present on the page. You can use https://fabianhenneke.github.io/Android-Password-Store/ as a test form. */</ID>
|
<ID>MaxLineLength:FeatureAndTrustDetection.kt$/* In order to add a new browser, do the following: 1. Obtain the .apk from a trusted source. For example, download it from the Play Store on your phone and use adb pull to get it onto your computer. We will assume that it is called browser.apk. 2. Run aapt dump badging browser.apk | grep package: | grep -Eo " name='[a-zA-Z0-9_\.]*" | cut -c8- to obtain the package name (actually, the application ID) of the app in the .apk. 3. Run apksigner verify --print-certs browser.apk | grep "#1 certificate SHA-256" | grep -Eo "[a-f0-9]{64}" | tr -d '\n' | xxd -r -p | base64 to calculate the hash of browser.apk's first signing certificate. Note: This will only work if the apk has a single signing certificate. Apps with multiple signers are very rare, so there is probably no need to add them. Refer to computeCertificatesHash to learn how the hash would be computed in this case. 4. Verify the package name and the hash, for example by asking other people to repeat the steps above. 5. Add an entry with the browser apps's package name and the hash to TRUSTED_BROWSER_CERTIFICATE_HASH. 6. Optionally, try adding the browser's package name to BROWSERS_WITH_SAVE_SUPPORT and check whether a save request to Password Store is triggered when you submit a registration form. 7. Optionally, try adding the browser's package name to BROWSERS_WITH_MULTI_ORIGIN_SUPPORT and check whether it correctly distinguishes web origins even if iframes are present on the page. You can use https://fabianhenneke.github.io/Android-Password-Store/ as a test form. */</ID>
|
||||||
<ID>MaxLineLength:FormField.kt$FormField$"\"$hint\", \"$fieldId\"${if (isFocused) ", focused" else ""}${if (isVisible) ", visible" else ""}, $webOrigin, $htmlAttributesDebug, $autofillHints"</ID>
|
<ID>MaxLineLength:FormField.kt$FormField$"\"$hint\", \"$fieldId\"${if (isFocused) ", focused" else ""}${if (isVisible) ", visible" else ""}, $webOrigin, $htmlAttributesDebug, $autofillHints"</ID>
|
||||||
<ID>ReturnCount:AutofillFormParser.kt$AutofillFormParser$private fun determineFormOrigin(context: Context): FormOrigin?</ID>
|
<ID>ReturnCount:AutofillFormParser.kt$AutofillFormParser$private fun determineFormOrigin(context: Context): FormOrigin?</ID>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
<SmellBaseline>
|
<SmellBaseline>
|
||||||
<ManuallySuppressedIssues/>
|
<ManuallySuppressedIssues>
|
||||||
|
<ID>TooGenericExceptionCaught:RunSuspendCatching.kt$e: Throwable</ID>
|
||||||
|
</ManuallySuppressedIssues>
|
||||||
<CurrentIssues>
|
<CurrentIssues>
|
||||||
<ID>InstanceOfCheckForException:RunSuspendCatching.kt$e is CancellationException</ID>
|
|
||||||
<ID>TooGenericExceptionCaught:RunSuspendCatching.kt$e: Throwable</ID>
|
<ID>TooGenericExceptionCaught:RunSuspendCatching.kt$e: Throwable</ID>
|
||||||
</CurrentIssues>
|
</CurrentIssues>
|
||||||
</SmellBaseline>
|
</SmellBaseline>
|
||||||
|
|
Loading…
Reference in a new issue