Compile against SDK 33 (#2023)
* Compile against SDK 33 * autofill-parser: fix warnings for SDK 33 upgrade * app: fix warnings for SDK 33 upgrade * Mark all clipboard content as sensitive from crypto activities * Skip Snackbar on Android 13 and above * detekt: raise `TooManyFunctions` limit to 15
This commit is contained in:
parent
9cd2f5f446
commit
ade73fd5bc
29 changed files with 210 additions and 71 deletions
|
@ -22,6 +22,9 @@ import app.passwordstore.databinding.ActivityOreoAutofillPublisherChangedBinding
|
|||
import app.passwordstore.util.autofill.AutofillMatcher
|
||||
import app.passwordstore.util.autofill.AutofillPublisherChangedException
|
||||
import app.passwordstore.util.extensions.asLog
|
||||
import app.passwordstore.util.extensions.getApplicationInfoCompat
|
||||
import app.passwordstore.util.extensions.getPackageInfoCompat
|
||||
import app.passwordstore.util.extensions.getParcelableExtraCompat
|
||||
import app.passwordstore.util.extensions.viewBinding
|
||||
import com.github.androidpasswordstore.autofillparser.FormOrigin
|
||||
import com.github.androidpasswordstore.autofillparser.computeCertificatesHash
|
||||
|
@ -93,7 +96,8 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
|
|||
this@AutofillPublisherChangedActivity,
|
||||
FormOrigin.App(appPackage)
|
||||
)
|
||||
val fillResponse = intent.getParcelableExtra<FillResponse>(EXTRA_FILL_RESPONSE_AFTER_RESET)
|
||||
val fillResponse =
|
||||
intent.getParcelableExtraCompat<FillResponse>(EXTRA_FILL_RESPONSE_AFTER_RESET)
|
||||
setResult(
|
||||
RESULT_OK,
|
||||
Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillResponse) }
|
||||
|
@ -106,11 +110,13 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
|
|||
private fun showPackageInfo() {
|
||||
runCatching {
|
||||
with(binding) {
|
||||
val packageInfo = packageManager.getPackageInfo(appPackage, PackageManager.GET_META_DATA)
|
||||
val packageInfo =
|
||||
packageManager.getPackageInfoCompat(appPackage, PackageManager.GET_META_DATA)
|
||||
val installTime = DateUtils.getRelativeTimeSpanString(packageInfo.firstInstallTime)
|
||||
warningAppInstallDate.text =
|
||||
getString(R.string.oreo_autofill_warning_publisher_install_time, installTime)
|
||||
val appInfo = packageManager.getApplicationInfo(appPackage, PackageManager.GET_META_DATA)
|
||||
val appInfo =
|
||||
packageManager.getApplicationInfoCompat(appPackage, PackageManager.GET_META_DATA)
|
||||
warningAppName.text =
|
||||
getString(
|
||||
R.string.oreo_autofill_warning_publisher_app_name,
|
||||
|
|
|
@ -10,6 +10,7 @@ import android.content.Intent
|
|||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.PersistableBundle
|
||||
import android.view.WindowManager
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.annotation.StringRes
|
||||
|
@ -68,8 +69,12 @@ open class BasePgpActivity : AppCompatActivity() {
|
|||
) {
|
||||
val clipboard = clipboard ?: return
|
||||
val clip = ClipData.newPlainText("pgp_handler_result_pm", text)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
clip.description.extras =
|
||||
PersistableBundle().apply { putBoolean("android.content.extra.IS_SENSITIVE", true) }
|
||||
}
|
||||
clipboard.setPrimaryClip(clip)
|
||||
if (showSnackbar) {
|
||||
if (showSnackbar && Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
snackbar(message = resources.getString(snackbarTextRes))
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +85,7 @@ open class BasePgpActivity : AppCompatActivity() {
|
|||
* clearing the clipboard.
|
||||
*/
|
||||
fun copyPasswordToClipboard(password: String?) {
|
||||
copyTextToClipboard(password, showSnackbar = false)
|
||||
copyTextToClipboard(password)
|
||||
|
||||
val clearAfter = settings.getString(PreferenceKeys.GENERAL_SHOW_TIME)?.toIntOrNull() ?: 45
|
||||
|
||||
|
@ -95,9 +100,6 @@ open class BasePgpActivity : AppCompatActivity() {
|
|||
} else {
|
||||
startService(service)
|
||||
}
|
||||
snackbar(message = resources.getString(R.string.clipboard_password_toast_text, clearAfter))
|
||||
} else {
|
||||
snackbar(message = resources.getString(R.string.clipboard_password_no_clear_toast_text))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ class DecryptActivity : BasePgpActivity() {
|
|||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> onBackPressed()
|
||||
android.R.id.home -> onBackPressedDispatcher.onBackPressed()
|
||||
R.id.edit_password -> editPassword()
|
||||
R.id.share_password_as_plaintext -> shareAsPlaintext()
|
||||
R.id.copy_password -> copyPasswordToClipboard(passwordEntry?.password)
|
||||
|
|
|
@ -262,7 +262,7 @@ class PasswordCreationActivity : BasePgpActivity() {
|
|||
when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
setResult(RESULT_CANCELED)
|
||||
onBackPressed()
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
R.id.save_password -> {
|
||||
copy = false
|
||||
|
|
|
@ -49,7 +49,7 @@ class SelectFolderActivity : AppCompatActivity(R.layout.select_folder_layout) {
|
|||
when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
setResult(RESULT_CANCELED)
|
||||
onBackPressed()
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
R.id.crypto_select -> selectFolder()
|
||||
else -> return super.onOptionsItemSelected(item)
|
||||
|
|
|
@ -69,7 +69,7 @@ class GitConfigActivity : BaseGitActivity() {
|
|||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
onBackPressed()
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
|
|
|
@ -202,7 +202,7 @@ class GitServerConfigActivity : BaseGitActivity() {
|
|||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
onBackPressed()
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
package app.passwordstore.ui.onboarding.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.addCallback
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import app.passwordstore.R
|
||||
|
||||
|
@ -14,13 +15,11 @@ class OnboardingActivity : AppCompatActivity(R.layout.activity_onboarding) {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
supportActionBar?.hide()
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
val callback = onBackPressedDispatcher.addCallback(enabled = false) { finishAffinity() }
|
||||
supportFragmentManager.addOnBackStackChangedListener {
|
||||
if (supportFragmentManager.backStackEntryCount == 0) {
|
||||
finishAffinity()
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
callback.isEnabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
*/
|
||||
package app.passwordstore.ui.passwords
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
@ -14,7 +13,6 @@ import android.view.Menu
|
|||
import android.view.MenuItem
|
||||
import android.view.MenuItem.OnActionExpandListener
|
||||
import android.view.WindowManager
|
||||
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission
|
||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.widget.SearchView
|
||||
|
@ -77,18 +75,6 @@ class PasswordStore : BaseGitActivity() {
|
|||
ViewModelProvider.AndroidViewModelFactory(application)
|
||||
}
|
||||
|
||||
private val storagePermissionRequest =
|
||||
registerForActivityResult(RequestPermission()) { granted ->
|
||||
if (granted) checkLocalRepository()
|
||||
}
|
||||
|
||||
private val directorySelectAction =
|
||||
registerForActivityResult(StartActivityForResult()) { result ->
|
||||
if (result.resultCode == RESULT_OK) {
|
||||
checkLocalRepository()
|
||||
}
|
||||
}
|
||||
|
||||
private val listRefreshAction =
|
||||
registerForActivityResult(StartActivityForResult()) { result ->
|
||||
if (result.resultCode == RESULT_OK) {
|
||||
|
@ -196,7 +182,6 @@ class PasswordStore : BaseGitActivity() {
|
|||
return super.onKeyDown(keyCode, event)
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_pwdstore)
|
||||
|
@ -313,12 +298,14 @@ class PasswordStore : BaseGitActivity() {
|
|||
}
|
||||
}
|
||||
R.id.refresh -> refreshPasswordList()
|
||||
android.R.id.home -> onBackPressed()
|
||||
android.R.id.home -> onBackPressedDispatcher.onBackPressed()
|
||||
else -> return super.onOptionsItemSelected(item)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
@Suppress("DEPRECATION")
|
||||
override fun onBackPressed() {
|
||||
if (getPasswordFragment()?.onBackPressedInActivity() != true) super.onBackPressed()
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import android.view.MenuItem
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import app.passwordstore.R
|
||||
import app.passwordstore.databinding.ActivityPreferenceRecyclerviewBinding
|
||||
import app.passwordstore.util.extensions.getParcelableCompat
|
||||
import app.passwordstore.util.extensions.viewBinding
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import de.Maxr1998.modernpreferences.Preference
|
||||
|
@ -84,7 +85,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
savedInstanceState
|
||||
?.getParcelable<PreferencesAdapter.SavedState>("adapter")
|
||||
?.getParcelableCompat<PreferencesAdapter.SavedState>("adapter")
|
||||
?.let(adapter::loadSavedState)
|
||||
binding.preferenceRecyclerView.adapter = adapter
|
||||
}
|
||||
|
@ -106,6 +107,8 @@ class SettingsActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
@Suppress("DEPRECATION")
|
||||
override fun onBackPressed() {
|
||||
if (!preferencesAdapter.goBack()) super.onBackPressed()
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ class SshKeyGenActivity : AppCompatActivity() {
|
|||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
onBackPressed()
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
|
|
|
@ -7,9 +7,11 @@ package app.passwordstore.util.autofill
|
|||
|
||||
import android.content.Context
|
||||
import android.content.IntentSender
|
||||
import android.os.Build
|
||||
import android.service.autofill.Dataset
|
||||
import android.service.autofill.FillCallback
|
||||
import android.service.autofill.FillResponse
|
||||
import android.service.autofill.Presentations
|
||||
import android.service.autofill.SaveInfo
|
||||
import android.view.inputmethod.InlineSuggestionsRequest
|
||||
import android.widget.inline.InlinePresentationSpec
|
||||
|
@ -60,6 +62,23 @@ constructor(
|
|||
intentSender: IntentSender,
|
||||
metadata: DatasetMetadata,
|
||||
imeSpec: InlinePresentationSpec?,
|
||||
): Dataset {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
makeIntentDataSetTiramisu(context, action, intentSender, metadata, imeSpec)
|
||||
} else {
|
||||
makeIntentDataSetR(context, action, intentSender, metadata, imeSpec)
|
||||
}
|
||||
}
|
||||
|
||||
/** Helper for creating an Autofill [Dataset]s for Android R and above. */
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
@Suppress("DEPRECATION")
|
||||
private fun makeIntentDataSetR(
|
||||
context: Context,
|
||||
action: AutofillAction,
|
||||
intentSender: IntentSender,
|
||||
metadata: DatasetMetadata,
|
||||
imeSpec: InlinePresentationSpec?,
|
||||
): Dataset {
|
||||
return Dataset.Builder(makeRemoteView(context, metadata)).run {
|
||||
fillWith(scenario, action, credentials = null)
|
||||
|
@ -74,6 +93,30 @@ constructor(
|
|||
}
|
||||
}
|
||||
|
||||
/** Helper for creating Autofill [Dataset]s for Android Tiramisu and above. */
|
||||
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||
private fun makeIntentDataSetTiramisu(
|
||||
context: Context,
|
||||
action: AutofillAction,
|
||||
intentSender: IntentSender,
|
||||
metadata: DatasetMetadata,
|
||||
imeSpec: InlinePresentationSpec?,
|
||||
): Dataset {
|
||||
val presentationsBuilder = Presentations.Builder()
|
||||
if (imeSpec != null) {
|
||||
val inlinePresentation = makeInlinePresentation(context, imeSpec, metadata)
|
||||
if (inlinePresentation != null) {
|
||||
presentationsBuilder.setInlinePresentation(inlinePresentation)
|
||||
}
|
||||
}
|
||||
val presentations = presentationsBuilder.build()
|
||||
return Dataset.Builder(presentations).run {
|
||||
fillWith(scenario, action, credentials = null)
|
||||
setAuthentication(intentSender)
|
||||
build()
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeMatchDataset(
|
||||
context: Context,
|
||||
file: File,
|
||||
|
|
|
@ -54,6 +54,7 @@ constructor(
|
|||
private val scenarioSupportsSave = scenario.hasPasswordFieldsToSave
|
||||
private val canBeSaved = saveFlags != null && scenarioSupportsSave
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun makeIntentDataset(
|
||||
context: Context,
|
||||
action: AutofillAction,
|
||||
|
@ -212,7 +213,7 @@ constructor(
|
|||
if (Build.VERSION.SDK_INT >= 28) {
|
||||
Dataset.Builder()
|
||||
} else {
|
||||
Dataset.Builder(makeRemoteView(context, makeEmptyMetadata()))
|
||||
@Suppress("DEPRECATION") Dataset.Builder(makeRemoteView(context, makeEmptyMetadata()))
|
||||
}
|
||||
return builder.run {
|
||||
if (scenario != null) fillWith(scenario, action, credentials)
|
||||
|
|
|
@ -10,7 +10,14 @@ import android.content.ClipboardManager
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManager.ApplicationInfoFlags
|
||||
import android.content.pm.PackageManager.PackageInfoFlags
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.util.Base64
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
|
@ -132,3 +139,45 @@ fun SharedPreferences.getString(key: String): String? = getString(key, null)
|
|||
fun String.base64(): String {
|
||||
return Base64.encodeToString(encodeToByteArray(), Base64.NO_WRAP)
|
||||
}
|
||||
|
||||
inline fun <reified T> Bundle.getParcelableCompat(key: String): T? {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
getParcelable(key, T::class.java)
|
||||
} else {
|
||||
@Suppress("DEPRECATION") getParcelable(key)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : Parcelable> Bundle.getParcelableArrayListCompat(
|
||||
key: String
|
||||
): ArrayList<T>? {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
getParcelableArrayList(key, T::class.java)
|
||||
} else {
|
||||
@Suppress("DEPRECATION") getParcelableArrayList(key)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : Parcelable> Intent.getParcelableExtraCompat(key: String): T? {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
getParcelableExtra(key, T::class.java)
|
||||
} else {
|
||||
@Suppress("DEPRECATION") getParcelableExtra(key)
|
||||
}
|
||||
}
|
||||
|
||||
fun PackageManager.getPackageInfoCompat(packageName: String, flags: Int): PackageInfo {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
getPackageInfo(packageName, PackageInfoFlags.of(flags.toLong()))
|
||||
} else {
|
||||
@Suppress("DEPRECATION") getPackageInfo(packageName, flags)
|
||||
}
|
||||
}
|
||||
|
||||
fun PackageManager.getApplicationInfoCompat(packageName: String, flags: Int): ApplicationInfo {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
getApplicationInfo(packageName, ApplicationInfoFlags.of(flags.toLong()))
|
||||
} else {
|
||||
@Suppress("DEPRECATION") getApplicationInfo(packageName, flags)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,11 @@ class ClipboardService : Service() {
|
|||
when (intent.action) {
|
||||
ACTION_CLEAR -> {
|
||||
clearClipboard()
|
||||
stopForeground(true)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
stopForeground(STOP_FOREGROUND_REMOVE)
|
||||
} else {
|
||||
@Suppress("DEPRECATION") stopForeground(true)
|
||||
}
|
||||
stopSelf()
|
||||
return super.onStartCommand(intent, flags, startId)
|
||||
}
|
||||
|
@ -55,7 +59,11 @@ class ClipboardService : Service() {
|
|||
withContext(Dispatchers.IO) { startTimer(time) }
|
||||
withContext(Dispatchers.Main) {
|
||||
clearClipboard()
|
||||
stopForeground(true)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
stopForeground(STOP_FOREGROUND_REMOVE)
|
||||
} else {
|
||||
@Suppress("DEPRECATION") stopForeground(true)
|
||||
}
|
||||
stopSelf()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import androidx.core.content.getSystemService
|
|||
import androidx.documentfile.provider.DocumentFile
|
||||
import app.passwordstore.R
|
||||
import app.passwordstore.data.repo.PasswordRepository
|
||||
import app.passwordstore.util.extensions.getParcelableExtraCompat
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.Calendar
|
||||
|
@ -29,7 +30,7 @@ class PasswordExportService : Service() {
|
|||
if (intent != null) {
|
||||
when (intent.action) {
|
||||
ACTION_EXPORT_PASSWORD -> {
|
||||
val uri = intent.getParcelableExtra<Uri>("uri")
|
||||
val uri = intent.getParcelableExtraCompat<Uri>("uri")
|
||||
if (uri != null) {
|
||||
val targetDirectory = DocumentFile.fromTreeUri(applicationContext, uri)
|
||||
|
||||
|
|
|
@ -33,8 +33,6 @@
|
|||
<string name="git_commit_move_text">Benenne %1$s in %2$s um.</string>
|
||||
<string name="git_commit_move_multiple_text">Verschiebe mehrere Passwörter nach %1$s.</string>
|
||||
<!-- PGPHandler -->
|
||||
<string name="clipboard_password_toast_text">Passwort ist in der Zwischenablage, du hast %d Sekunden, um es einzufügen.</string>
|
||||
<string name="clipboard_password_no_clear_toast_text">Passwort wurde in die Zwischenablage kopiert</string>
|
||||
<string name="clipboard_copied_text">In die Zwischenablage kopiert</string>
|
||||
<string name="file_toast_text">Bitte setze einen Pfad</string>
|
||||
<string name="path_toast_text">Bitte setze einen Pfad</string>
|
||||
|
|
|
@ -37,8 +37,6 @@
|
|||
<string name="git_commit_move_text">Renommer %1$sà %2$s. </string>
|
||||
<string name="git_commit_move_multiple_text">Déplacement de mots de passe vers %1$s.</string>
|
||||
<!-- PGPHandler -->
|
||||
<string name="clipboard_password_toast_text">Mot de passe copié dans le presse papier, vous avez %d secondes pour coller celui-ci.</string>
|
||||
<string name="clipboard_password_no_clear_toast_text">Mot de passe copié dans le presse-papiers</string>
|
||||
<string name="clipboard_copied_text">Copié dans le presse-papiers</string>
|
||||
<string name="file_toast_text">Veuillez fournir un nom de fichier</string>
|
||||
<string name="path_toast_text">Veuillez fournir un chemin d\'accès au fichier</string>
|
||||
|
|
|
@ -37,8 +37,6 @@
|
|||
<string name="git_commit_move_text">Mudar nome %1$s a %2$s.</string>
|
||||
<string name="git_commit_move_multiple_text">Mover varios contrasinais a %1$s.</string>
|
||||
<!-- PGPHandler -->
|
||||
<string name="clipboard_password_toast_text">Contrasinal copiado ao portapapeis, tes %d segundos para pegala nalgures.</string>
|
||||
<string name="clipboard_password_no_clear_toast_text">Contrasinal copiado ao portapapeis</string>
|
||||
<string name="clipboard_copied_text">Copiada ó portapapeis</string>
|
||||
<string name="file_toast_text">Debes proporcionar un nome de ficheiro</string>
|
||||
<string name="path_toast_text">Por favor indica a ruta ao ficheiro</string>
|
||||
|
|
|
@ -37,8 +37,6 @@
|
|||
<string name="git_commit_move_text">Rinomina %1$s in %2$s.</string>
|
||||
<string name="git_commit_move_multiple_text">Sposta più password in %1$s.</string>
|
||||
<!-- PGPHandler -->
|
||||
<string name="clipboard_password_toast_text">Password copiata negli appunti, hai %d secondi per incollarla da qualche parte.</string>
|
||||
<string name="clipboard_password_no_clear_toast_text">Password copiata negli appunti</string>
|
||||
<string name="clipboard_copied_text">Copiato negli appunti</string>
|
||||
<string name="file_toast_text">Sei pregato di fornire il nome di un file</string>
|
||||
<string name="path_toast_text">Sei pregato di fornire il percorso di un file</string>
|
||||
|
|
|
@ -37,8 +37,6 @@
|
|||
<string name="git_commit_move_text">Renomear %1$s para %2$s.</string>
|
||||
<string name="git_commit_move_multiple_text">Mova múltiplas senhas para %1$s.</string>
|
||||
<!-- PGPHandler -->
|
||||
<string name="clipboard_password_toast_text">Senha copiada para área de transferência, você tem %d segundos para colá-la em algum lugar.</string>
|
||||
<string name="clipboard_password_no_clear_toast_text">Senha copiada para área de transferência</string>
|
||||
<string name="clipboard_copied_text">Copiado para a área de transferência</string>
|
||||
<string name="file_toast_text">Por favor, informe um nome de arquivo</string>
|
||||
<string name="path_toast_text">Por favor, forneça o caminho do arquivo</string>
|
||||
|
|
|
@ -41,8 +41,6 @@
|
|||
<string name="git_commit_move_text">Переименовать %1$sв%2$s.</string>
|
||||
<string name="git_commit_move_multiple_text">Переместить несколько паролей в %1$s.</string>
|
||||
<!-- PGPHandler -->
|
||||
<string name="clipboard_password_toast_text">Пароль скопирован в буфер обмена, у вас есть %d секунд чтобы вставить его.</string>
|
||||
<string name="clipboard_password_no_clear_toast_text">Пароль скопирован в буфер обмена</string>
|
||||
<string name="clipboard_copied_text">Скопировано в буфер обмена</string>
|
||||
<string name="file_toast_text">Пожалуйста, укажите имя файла</string>
|
||||
<string name="path_toast_text">Пожалуйста, задайте путь к файлу</string>
|
||||
|
|
|
@ -45,8 +45,6 @@
|
|||
<string name="git_commit_move_multiple_text">Move multiple passwords to %1$s.</string>
|
||||
|
||||
<!-- PGPHandler -->
|
||||
<string name="clipboard_password_toast_text">Password copied to clipboard, you have %d seconds to paste it somewhere.</string>
|
||||
<string name="clipboard_password_no_clear_toast_text">Password copied to clipboard</string>
|
||||
<string name="clipboard_copied_text">Copied to clipboard</string>
|
||||
<string name="file_toast_text">Please provide a file name</string>
|
||||
<string name="path_toast_text">Please provide a file path</string>
|
||||
|
|
|
@ -7,7 +7,9 @@ package com.github.androidpasswordstore.autofillparser
|
|||
import android.app.assist.AssistStructure
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManager.ApplicationInfoFlags
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.autofill.AutofillId
|
||||
import androidx.annotation.RequiresApi
|
||||
|
@ -41,7 +43,15 @@ public sealed class FormOrigin(public open val identifier: String) {
|
|||
is Web -> identifier
|
||||
is App -> {
|
||||
val info =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
context.packageManager.getApplicationInfo(
|
||||
identifier,
|
||||
ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong())
|
||||
)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
context.packageManager.getApplicationInfo(identifier, PackageManager.GET_META_DATA)
|
||||
}
|
||||
val label = context.packageManager.getApplicationLabel(info)
|
||||
if (untrusted) "“$label”" else "$label"
|
||||
}
|
||||
|
|
|
@ -54,7 +54,15 @@ public fun computeCertificatesHash(context: Context, appPackage: String): String
|
|||
val stableHashOld = stableHash(signaturesOld.map { it.toByteArray() })
|
||||
if (Build.VERSION.SDK_INT >= 28) {
|
||||
val info =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
context.packageManager.getPackageInfo(
|
||||
appPackage,
|
||||
PackageManager.PackageInfoFlags.of(PackageManager.GET_SIGNING_CERTIFICATES.toLong())
|
||||
)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
context.packageManager.getPackageInfo(appPackage, PackageManager.GET_SIGNING_CERTIFICATES)
|
||||
}
|
||||
val signaturesNew =
|
||||
info.signingInfo.signingCertificateHistory ?: info.signingInfo.apkContentsSigners
|
||||
val stableHashNew = stableHash(signaturesNew.map { it.toByteArray() })
|
||||
|
|
|
@ -5,8 +5,11 @@
|
|||
package com.github.androidpasswordstore.autofillparser
|
||||
|
||||
import android.app.assist.AssistStructure
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.service.autofill.Dataset
|
||||
import android.service.autofill.Field
|
||||
import android.view.autofill.AutofillId
|
||||
import android.view.autofill.AutofillValue
|
||||
import androidx.annotation.RequiresApi
|
||||
|
@ -54,17 +57,19 @@ public sealed class AutofillScenario<out T : Any> {
|
|||
return try {
|
||||
Builder<AutofillId>()
|
||||
.apply {
|
||||
username = clientState.getParcelable(BUNDLE_KEY_USERNAME_ID)
|
||||
username = clientState.getParcelableCompat(BUNDLE_KEY_USERNAME_ID)
|
||||
fillUsername = clientState.getBoolean(BUNDLE_KEY_FILL_USERNAME)
|
||||
otp = clientState.getParcelable(BUNDLE_KEY_OTP_ID)
|
||||
otp = clientState.getParcelableCompat(BUNDLE_KEY_OTP_ID)
|
||||
currentPassword.addAll(
|
||||
clientState.getParcelableArrayList(BUNDLE_KEY_CURRENT_PASSWORD_IDS) ?: emptyList()
|
||||
clientState.getParcelableArrayListCompat(BUNDLE_KEY_CURRENT_PASSWORD_IDS)
|
||||
?: emptyList()
|
||||
)
|
||||
newPassword.addAll(
|
||||
clientState.getParcelableArrayList(BUNDLE_KEY_NEW_PASSWORD_IDS) ?: emptyList()
|
||||
clientState.getParcelableArrayListCompat(BUNDLE_KEY_NEW_PASSWORD_IDS) ?: emptyList()
|
||||
)
|
||||
genericPassword.addAll(
|
||||
clientState.getParcelableArrayList(BUNDLE_KEY_GENERIC_PASSWORD_IDS) ?: emptyList()
|
||||
clientState.getParcelableArrayListCompat(BUNDLE_KEY_GENERIC_PASSWORD_IDS)
|
||||
?: emptyList()
|
||||
)
|
||||
}
|
||||
.build()
|
||||
|
@ -73,6 +78,24 @@ public sealed class AutofillScenario<out T : Any> {
|
|||
null
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified T> Bundle.getParcelableCompat(key: String): T? {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
getParcelable(key, T::class.java)
|
||||
} else {
|
||||
@Suppress("DEPRECATION") getParcelable(key)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified T : Parcelable> Bundle.getParcelableArrayListCompat(
|
||||
key: String
|
||||
): ArrayList<T>? {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
getParcelableArrayList(key, T::class.java)
|
||||
} else {
|
||||
@Suppress("DEPRECATION") getParcelableArrayList(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class Builder<T : Any> {
|
||||
|
@ -231,7 +254,11 @@ public fun Dataset.Builder.fillWith(
|
|||
scenario.otp -> credentialsToFill.otp
|
||||
else -> credentialsToFill.password
|
||||
}
|
||||
setValue(field, AutofillValue.forText(value))
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
setField(field, Field.Builder().setValue(AutofillValue.forText(value)).build())
|
||||
} else {
|
||||
@Suppress("DEPRECATION") setValue(field, AutofillValue.forText(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ package com.github.androidpasswordstore.autofillparser
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManager.ResolveInfoFlags
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
|
@ -247,7 +248,15 @@ public fun getInstalledBrowsersWithAutofillSupportLevel(
|
|||
): List<Pair<String, BrowserAutofillSupportLevel>> {
|
||||
val testWebIntent = Intent(Intent.ACTION_VIEW).apply { data = Uri.parse("https://example.org") }
|
||||
val installedBrowsers =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
context.packageManager.queryIntentActivities(
|
||||
testWebIntent,
|
||||
ResolveInfoFlags.of(PackageManager.MATCH_ALL.toLong())
|
||||
)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
context.packageManager.queryIntentActivities(testWebIntent, PackageManager.MATCH_ALL)
|
||||
}
|
||||
return installedBrowsers
|
||||
.map { it to getBrowserAutofillSupportLevel(context, it.activityInfo.packageName) }
|
||||
.filter { it.first.isDefault || it.second != BrowserAutofillSupportLevel.None }
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.gradle.kotlin.dsl.configure
|
|||
object AndroidCommon {
|
||||
fun configure(project: Project) {
|
||||
project.extensions.configure<TestedExtension> {
|
||||
setCompileSdkVersion(32)
|
||||
setCompileSdkVersion(33)
|
||||
defaultConfig {
|
||||
minSdk = 23
|
||||
targetSdk = 31
|
||||
|
|
|
@ -158,11 +158,11 @@ complexity:
|
|||
TooManyFunctions:
|
||||
active: true
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
thresholdInFiles: 11
|
||||
thresholdInClasses: 11
|
||||
thresholdInInterfaces: 11
|
||||
thresholdInObjects: 11
|
||||
thresholdInEnums: 11
|
||||
thresholdInFiles: 15
|
||||
thresholdInClasses: 15
|
||||
thresholdInInterfaces: 15
|
||||
thresholdInObjects: 15
|
||||
thresholdInEnums: 15
|
||||
ignoreDeprecated: false
|
||||
ignorePrivate: false
|
||||
ignoreOverridden: false
|
||||
|
|
Loading…
Reference in a new issue