diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index be83284a..43336cba 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -17,6 +17,7 @@
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 312bfb02..d318df31 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
+### Added
+
+- On Android 11, Autofill will use the new [inline autofill](https://developer.android.com/guide/topics/text/ime-autofill#configure-provider) UI that integrates Autofill results into your keyboard app.
+
### Fixed
- Cancelling the Autofill "Generate password" action now correctly returns you to the original app.
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index e56ebd52..87e436a0 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -89,6 +89,7 @@ dependencies {
compileOnly(Dependencies.AndroidX.annotation)
implementation(Dependencies.AndroidX.activity_ktx)
implementation(Dependencies.AndroidX.appcompat)
+ implementation(Dependencies.AndroidX.autofill)
implementation(Dependencies.AndroidX.biometric)
implementation(Dependencies.AndroidX.constraint_layout)
implementation(Dependencies.AndroidX.core_ktx)
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillResponseBuilder.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillResponseBuilder.kt
index ec3d2b77..2c62f935 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillResponseBuilder.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillResponseBuilder.kt
@@ -12,7 +12,8 @@ import android.service.autofill.Dataset
import android.service.autofill.FillCallback
import android.service.autofill.FillResponse
import android.service.autofill.SaveInfo
-import android.widget.RemoteViews
+import android.view.inputmethod.InlineSuggestionsRequest
+import android.widget.inline.InlinePresentationSpec
import androidx.annotation.RequiresApi
import com.github.ajalt.timberkt.e
import com.github.androidpasswordstore.autofillparser.AutofillAction
@@ -41,70 +42,85 @@ class AutofillResponseBuilder(form: FillableForm) {
scenario.fieldsToSave.minus(listOfNotNull(scenario.username)).isNotEmpty()
private val canBeSaved = saveFlags != null && scenarioSupportsSave
- private fun makePlaceholderDataset(
- remoteView: RemoteViews,
+ private fun makeIntentDataset(
+ context: Context,
+ action: AutofillAction,
intentSender: IntentSender,
- action: AutofillAction
+ metadata: DatasetMetadata,
+ imeSpec: InlinePresentationSpec?,
): Dataset {
- return Dataset.Builder(remoteView).run {
+ return Dataset.Builder(makeRemoteView(context, metadata)).run {
fillWith(scenario, action, credentials = null)
setAuthentication(intentSender)
+ if (imeSpec != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ val inlinePresentation = makeInlinePresentation(context, imeSpec, metadata)
+ if (inlinePresentation != null) {
+ setInlinePresentation(inlinePresentation)
+ }
+ }
build()
}
}
- private fun makeMatchDataset(context: Context, file: File): Dataset? {
+ private fun makeMatchDataset(context: Context, file: File, imeSpec: InlinePresentationSpec?): Dataset? {
if (scenario.fieldsToFillOn(AutofillAction.Match).isEmpty()) return null
- val remoteView = makeFillMatchRemoteView(context, file, formOrigin)
+ val metadata = makeFillMatchMetadata(context, file)
val intentSender = AutofillDecryptActivity.makeDecryptFileIntentSender(file, context)
- return makePlaceholderDataset(remoteView, intentSender, AutofillAction.Match)
+ return makeIntentDataset(context, AutofillAction.Match, intentSender, metadata, imeSpec)
}
- private fun makeSearchDataset(context: Context): Dataset? {
+ private fun makeSearchDataset(context: Context, imeSpec: InlinePresentationSpec?): Dataset? {
if (scenario.fieldsToFillOn(AutofillAction.Search).isEmpty()) return null
- val remoteView = makeSearchAndFillRemoteView(context, formOrigin)
+ val metadata = makeSearchAndFillMetadata(context)
val intentSender =
AutofillFilterView.makeMatchAndDecryptFileIntentSender(context, formOrigin)
- return makePlaceholderDataset(remoteView, intentSender, AutofillAction.Search)
+ return makeIntentDataset(context, AutofillAction.Search, intentSender, metadata, imeSpec)
}
- private fun makeGenerateDataset(context: Context): Dataset? {
+ private fun makeGenerateDataset(context: Context, imeSpec: InlinePresentationSpec?): Dataset? {
if (scenario.fieldsToFillOn(AutofillAction.Generate).isEmpty()) return null
- val remoteView = makeGenerateAndFillRemoteView(context, formOrigin)
+ val metadata = makeGenerateAndFillMetadata(context)
val intentSender = AutofillSaveActivity.makeSaveIntentSender(context, null, formOrigin)
- return makePlaceholderDataset(remoteView, intentSender, AutofillAction.Generate)
+ return makeIntentDataset(context, AutofillAction.Generate, intentSender, metadata, imeSpec)
}
- private fun makeFillOtpFromSmsDataset(context: Context): Dataset? {
+ private fun makeFillOtpFromSmsDataset(context: Context, imeSpec: InlinePresentationSpec?): Dataset? {
if (scenario.fieldsToFillOn(AutofillAction.FillOtpFromSms).isEmpty()) return null
if (!AutofillSmsActivity.shouldOfferFillFromSms(context)) return null
- val remoteView = makeFillOtpFromSmsRemoteView(context, formOrigin)
+ val metadata = makeFillOtpFromSmsMetadata(context)
val intentSender = AutofillSmsActivity.makeFillOtpFromSmsIntentSender(context)
- return makePlaceholderDataset(remoteView, intentSender, AutofillAction.FillOtpFromSms)
+ return makeIntentDataset(context, AutofillAction.FillOtpFromSms, intentSender, metadata, imeSpec)
}
private fun makePublisherChangedDataset(
context: Context,
- publisherChangedException: AutofillPublisherChangedException
+ publisherChangedException: AutofillPublisherChangedException,
+ imeSpec: InlinePresentationSpec?
): Dataset {
- val remoteView = makeWarningRemoteView(context)
+ val metadata = makeWarningMetadata(context)
// If the user decides to trust the new publisher, they can choose reset the list of
// matches. In this case we need to immediately show a new `FillResponse` as if the app were
// autofilled for the first time. This `FillResponse` needs to be returned as a result from
// `AutofillPublisherChangedActivity`, which is why we create and pass it on here.
- val fillResponseAfterReset = makeFillResponse(context, emptyList())
+ val fillResponseAfterReset = makeFillResponse(context, null, emptyList())
val intentSender = AutofillPublisherChangedActivity.makePublisherChangedIntentSender(
context, publisherChangedException, fillResponseAfterReset
)
- return makePlaceholderDataset(remoteView, intentSender, AutofillAction.Match)
+ return makeIntentDataset(context, AutofillAction.Match, intentSender, metadata, imeSpec)
}
private fun makePublisherChangedResponse(
context: Context,
+ inlineSuggestionsRequest: InlineSuggestionsRequest?,
publisherChangedException: AutofillPublisherChangedException
): FillResponse {
+ val imeSpec = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ inlineSuggestionsRequest?.inlinePresentationSpecs?.firstOrNull()
+ } else {
+ null
+ }
return FillResponse.Builder().run {
- addDataset(makePublisherChangedDataset(context, publisherChangedException))
+ addDataset(makePublisherChangedDataset(context, publisherChangedException, imeSpec))
setIgnoredIds(*ignoredIds.toTypedArray())
build()
}
@@ -127,28 +143,36 @@ class AutofillResponseBuilder(form: FillableForm) {
}
}
- private fun makeFillResponse(context: Context, matchedFiles: List): FillResponse? {
- var hasDataset = false
+ private fun makeFillResponse(context: Context, inlineSuggestionsRequest: InlineSuggestionsRequest?, matchedFiles: List): FillResponse? {
+ var datasetCount = 0
+ val imeSpecs: List = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ inlineSuggestionsRequest?.inlinePresentationSpecs
+ } else {
+ null
+ } ?: emptyList()
return FillResponse.Builder().run {
for (file in matchedFiles) {
- makeMatchDataset(context, file)?.let {
- hasDataset = true
+ makeMatchDataset(context, file, imeSpecs.getOrNull(datasetCount))?.let {
+ datasetCount++
addDataset(it)
}
}
- makeSearchDataset(context)?.let {
- hasDataset = true
+ makeSearchDataset(context, imeSpecs.getOrNull(datasetCount))?.let {
+ datasetCount++
addDataset(it)
}
- makeGenerateDataset(context)?.let {
- hasDataset = true
+ makeGenerateDataset(context, imeSpecs.getOrNull(datasetCount))?.let {
+ datasetCount++
addDataset(it)
}
- makeFillOtpFromSmsDataset(context)?.let {
- hasDataset = true
+ makeFillOtpFromSmsDataset(context, imeSpecs.getOrNull(datasetCount))?.let {
+ datasetCount++
addDataset(it)
}
- if (!hasDataset) return null
+ if (datasetCount == 0) return null
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ setHeader(makeRemoteView(context, makeHeaderMetadata(formOrigin.getPrettyIdentifier(context, untrusted = true))))
+ }
makeSaveInfo()?.let { setSaveInfo(it) }
setClientState(clientState)
setIgnoredIds(*ignoredIds.toTypedArray())
@@ -159,14 +183,14 @@ class AutofillResponseBuilder(form: FillableForm) {
/**
* Creates and returns a suitable [FillResponse] to the Autofill framework.
*/
- fun fillCredentials(context: Context, callback: FillCallback) {
+ fun fillCredentials(context: Context, inlineSuggestionsRequest: InlineSuggestionsRequest?, callback: FillCallback) {
AutofillMatcher.getMatchesFor(context, formOrigin).fold(
success = { matchedFiles ->
- callback.onSuccess(makeFillResponse(context, matchedFiles))
+ callback.onSuccess(makeFillResponse(context, inlineSuggestionsRequest, matchedFiles))
},
failure = { e ->
e(e)
- callback.onSuccess(makePublisherChangedResponse(context, e))
+ callback.onSuccess(makePublisherChangedResponse(context, inlineSuggestionsRequest, e))
}
)
}
@@ -178,14 +202,17 @@ class AutofillResponseBuilder(form: FillableForm) {
clientState: Bundle,
action: AutofillAction
): Dataset {
- val remoteView = makePlaceholderRemoteView(context)
val scenario = AutofillScenario.fromBundle(clientState)
// Before Android P, Datasets used for fill-in had to come with a RemoteViews, even
- // though they are never shown.
+ // though they are rarely shown.
+ // FIXME: We should clone the original dataset here and add the credentials to be filled
+ // in. Otherwise, the entry in the cached list of datasets will be overwritten by the
+ // fill-in dataset without any visual representation. This causes it to be missing from
+ // the Autofill suggestions shown after the user clears the filled out form fields.
val builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
Dataset.Builder()
} else {
- Dataset.Builder(remoteView)
+ Dataset.Builder(makeRemoteView(context, makeEmptyMetadata()))
}
return builder.run {
if (scenario != null) fillWith(scenario, action, credentials)
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillViewUtils.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillViewUtils.kt
index 5e8061a2..49e0d3e3 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillViewUtils.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillViewUtils.kt
@@ -4,64 +4,110 @@
*/
package com.zeapo.pwdstore.autofill.oreo
+import android.annotation.SuppressLint
+import android.app.PendingIntent
import android.content.Context
+import android.content.Intent
+import android.content.res.Resources
+import android.graphics.drawable.Icon
+import android.os.Build
+import android.service.autofill.InlinePresentation
+import android.view.View
import android.widget.RemoteViews
-import com.github.androidpasswordstore.autofillparser.FormOrigin
+import android.widget.inline.InlinePresentationSpec
+import androidx.annotation.DrawableRes
+import androidx.autofill.inline.UiVersions
+import androidx.autofill.inline.v1.InlineSuggestionUi
+import com.zeapo.pwdstore.PasswordStore
import com.zeapo.pwdstore.R
import com.zeapo.pwdstore.utils.PasswordRepository
import java.io.File
-private fun makeRemoteView(
- context: Context,
- title: String,
- summary: String,
- iconRes: Int
-): RemoteViews {
+data class DatasetMetadata(val title: String, val subtitle: String?, @DrawableRes val iconRes: Int)
+
+fun makeRemoteView(context: Context, metadata: DatasetMetadata): RemoteViews {
return RemoteViews(context.packageName, R.layout.oreo_autofill_dataset).apply {
- setTextViewText(R.id.title, title)
- setTextViewText(R.id.summary, summary)
- setImageViewResource(R.id.icon, iconRes)
+ setTextViewText(R.id.title, metadata.title)
+ if (metadata.subtitle != null) {
+ setTextViewText(R.id.summary, metadata.subtitle)
+ } else {
+ setViewVisibility(R.id.summary, View.GONE)
+ }
+ if (metadata.iconRes != Resources.ID_NULL) {
+ setImageViewResource(R.id.icon, metadata.iconRes)
+ } else {
+ setViewVisibility(R.id.icon, View.GONE)
+ }
}
}
-fun makeFillMatchRemoteView(context: Context, file: File, formOrigin: FormOrigin): RemoteViews {
- val title = formOrigin.getPrettyIdentifier(context, untrusted = false)
+@SuppressLint("RestrictedApi")
+fun makeInlinePresentation(context: Context, imeSpec: InlinePresentationSpec, metadata: DatasetMetadata): InlinePresentation? {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
+ return null
+
+ if (UiVersions.INLINE_UI_VERSION_1 !in UiVersions.getVersions(imeSpec.style))
+ return null
+
+ val launchIntent = PendingIntent.getActivity(context, 0, Intent(context, PasswordStore::class.java), 0)
+ val slice = InlineSuggestionUi.newContentBuilder(launchIntent).run {
+ setTitle(metadata.title)
+ if (metadata.subtitle != null)
+ setSubtitle(metadata.subtitle)
+ setContentDescription(if (metadata.subtitle != null) "${metadata.title} - ${metadata.subtitle}" else metadata.title)
+ setStartIcon(Icon.createWithResource(context, metadata.iconRes))
+ build().slice
+ }
+
+ return InlinePresentation(slice, imeSpec, false)
+}
+
+
+fun makeFillMatchMetadata(context: Context, file: File): DatasetMetadata {
val directoryStructure = AutofillPreferences.directoryStructure(context)
val relativeFile = file.relativeTo(PasswordRepository.getRepositoryDirectory())
- val summary = directoryStructure.getUsernameFor(relativeFile)
- ?: directoryStructure.getPathToIdentifierFor(relativeFile) ?: ""
- val iconRes = R.drawable.ic_person_black_24dp
- return makeRemoteView(context, title, summary, iconRes)
+ val title = directoryStructure.getIdentifierFor(relativeFile)
+ ?: directoryStructure.getAccountPartFor(relativeFile)!!
+ val subtitle = directoryStructure.getAccountPartFor(relativeFile)
+ return DatasetMetadata(
+ title,
+ subtitle,
+ R.drawable.ic_person_black_24dp
+ )
}
-fun makeSearchAndFillRemoteView(context: Context, formOrigin: FormOrigin): RemoteViews {
- val title = formOrigin.getPrettyIdentifier(context, untrusted = true)
- val summary = context.getString(R.string.oreo_autofill_search_in_store)
- val iconRes = R.drawable.ic_search_black_24dp
- return makeRemoteView(context, title, summary, iconRes)
-}
+fun makeSearchAndFillMetadata(context: Context) = DatasetMetadata(
+ context.getString(R.string.oreo_autofill_search_in_store),
+ null,
+ R.drawable.ic_search_black_24dp
+)
-fun makeGenerateAndFillRemoteView(context: Context, formOrigin: FormOrigin): RemoteViews {
- val title = formOrigin.getPrettyIdentifier(context, untrusted = true)
- val summary = context.getString(R.string.oreo_autofill_generate_password)
- val iconRes = R.drawable.ic_autofill_new_password
- return makeRemoteView(context, title, summary, iconRes)
-}
+fun makeGenerateAndFillMetadata(context: Context) = DatasetMetadata(
+ context.getString(R.string.oreo_autofill_generate_password),
+ null,
+ R.drawable.ic_autofill_new_password
+)
-fun makeFillOtpFromSmsRemoteView(context: Context, formOrigin: FormOrigin): RemoteViews {
- val title = formOrigin.getPrettyIdentifier(context, untrusted = true)
- val summary = context.getString(R.string.oreo_autofill_fill_otp_from_sms)
- val iconRes = R.drawable.ic_autofill_sms
- return makeRemoteView(context, title, summary, iconRes)
-}
+fun makeFillOtpFromSmsMetadata(context: Context) = DatasetMetadata(
+ context.getString(R.string.oreo_autofill_fill_otp_from_sms),
+ null,
+ R.drawable.ic_autofill_sms
+)
-fun makePlaceholderRemoteView(context: Context): RemoteViews {
- return makeRemoteView(context, "PLACEHOLDER", "PLACEHOLDER", R.mipmap.ic_launcher)
-}
+fun makeEmptyMetadata() = DatasetMetadata(
+ "PLACEHOLDER",
+ "PLACEHOLDER",
+ R.mipmap.ic_launcher
+)
-fun makeWarningRemoteView(context: Context): RemoteViews {
- val title = context.getString(R.string.oreo_autofill_warning_publisher_dataset_title)
- val summary = context.getString(R.string.oreo_autofill_warning_publisher_dataset_summary)
- val iconRes = R.drawable.ic_warning_red_24dp
- return makeRemoteView(context, title, summary, iconRes)
-}
+fun makeWarningMetadata(context: Context) = DatasetMetadata(
+ context.getString(R.string.oreo_autofill_warning_publisher_dataset_title),
+ context.getString(R.string.oreo_autofill_warning_publisher_dataset_summary),
+ R.drawable.ic_warning_red_24dp
+)
+
+fun makeHeaderMetadata(title: String) = DatasetMetadata(
+ title,
+ null,
+ 0
+)
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/OreoAutofillService.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/OreoAutofillService.kt
index ecec6747..10831cc5 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/OreoAutofillService.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/OreoAutofillService.kt
@@ -86,7 +86,13 @@ class OreoAutofillService : AutofillService() {
callback.onSuccess(null)
return
}
- AutofillResponseBuilder(formToFill).fillCredentials(this, callback)
+ val inlineSuggestionsRequest =
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ request.inlineSuggestionsRequest
+ } else {
+ null
+ }
+ AutofillResponseBuilder(formToFill).fillCredentials(this, inlineSuggestionsRequest, callback)
}
override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) {
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillFilterActivity.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillFilterActivity.kt
index f22c6596..25919ad5 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillFilterActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillFilterActivity.kt
@@ -162,6 +162,13 @@ class AutofillFilterView : AppCompatActivity() {
setText(initialSearch, TextView.BufferType.EDITABLE)
addTextChangedListener { updateSearch() }
}
+ origin.text = buildSpannedString {
+ append(getString(R.string.oreo_autofill_select_and_fill_into))
+ append("\n")
+ bold {
+ append(formOrigin.getPrettyIdentifier(applicationContext, untrusted = true))
+ }
+ }
strictDomainSearch.apply {
visibility = if (formOrigin is FormOrigin.Web) View.VISIBLE else View.GONE
isChecked = formOrigin is FormOrigin.Web
diff --git a/app/src/main/res/layout/activity_oreo_autofill_filter.xml b/app/src/main/res/layout/activity_oreo_autofill_filter.xml
index a3718b43..8e671e30 100644
--- a/app/src/main/res/layout/activity_oreo_autofill_filter.xml
+++ b/app/src/main/res/layout/activity_oreo_autofill_filter.xml
@@ -14,16 +14,28 @@
+
+
+ app:layout_constraintTop_toBottomOf="@id/origin">
Passwort unverschlüsselt senden an…
App Icon
+ Eintrag auswählen für Autofill inPhishing-resistente SucheKeine Ergebnisse.Speichern aufgrund eines internen Fehlers fehlgeschlagenDiese App wird derzeit nicht unterstütztDie Passwörter stimmen nicht überein
- Passwort generieren…
+ Eintrag erstellen
+ Eintrag suchen
+ Code aus SMS einfügenDie derzeit installierte App versucht, Ihre Anmeldeinformationen zu stehlen, indem sie vorgibt, eine vertrauenswürdige App zu sein.\n\nVersuchen Sie die App zu deinstallieren und installieren Sie sie erneut aus einer vertrauenswürdigen Quelle wie dem Play Store, Amazon Appstore, F-Droid oder dem Shop Ihres Telefonherstellers.Installiert: %1$sWarnung
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index c64287b5..f19b6817 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -130,11 +130,9 @@
Coincide con %1$sSin resultados.
- Buscar en la tienda…Error al guardar debido a un error internoEsta aplicación no es compatible actualmenteLas contraseñas no coinciden
- Generar contraseña…Instalada: %1$sInformación avanzadaMantener el Autocompletado desactivado
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 557591e8..10fa1130 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -185,17 +185,15 @@
Apparier avec %1$sEffacer l’appairage actuelAucun résultat.
- Rechercher dans le dépôt…Échec de la sauvegarde : erreur interneCette application n\'est actuellement pas prise en chargeLes mots de passe ne coïncident pas
- Générer un mot de passe…
- Extraire le code depuis un SMS…
+ Extraire le code depuis un SMSL\'éditeur de cette application a changé depuis que vous avez appairé un mot de passe avec celle-ci:L\'application actuellement installée peut essayer de voler vos identifiants en faisant semblant d\'être une application de confiance.\n\nEssayez de désinstaller et de réinstaller l\'application à partir d\'une source fiable, comme le Play Store, l\'AppStore d\'Amazon, le F-Droid ou la boutique du fabricant de votre téléphone.Installé : %1$sAvertissement
- Appuyez pour en savoir plus…
+ Appuyez pour en savoir plusTentative possible d\'hameçonnageRemplir et enregistrer les identifiantsRemplir les identifiants
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index cef14227..c45b2705 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -187,12 +187,10 @@
Combinar com %1$sLimpar correspondências existentesSem resultados.
- Pesquisar no armazenamento…Falha ao salvar devido a um erro internoEste app não é suportado no momentoAs senhas não coincidem
- Gerar senha…
- Extrair código do SMS…
+ Extrair código do SMSNúmero máximo de correspondências (%1$d) atingidas; limpar correspondências antes de adicionar novas.O editor deste aplicativo mudou desde a primeira vez que você associou uma entrada no Password Store:O aplicativo atualmente instalado pode estar tentando roubar suas credenciais fingindo ser um aplicativo confiável.\n\nTente desinstalar e reinstalar o aplicativo de uma fonte confiável, como a Play Store, Amazon Appstore, F-Droid ou a loja do fabricante do seu telefone.
@@ -201,7 +199,7 @@
Manter o preenchimento automático desativadoReativar preenchimento automáticoAlerta
- Toque para detalhes…
+ Toque para detalhesPossível tentativa de phishingPreencher e salvar credenciaisPreencher as credenciais
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index f9340b41..baa49c74 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -191,12 +191,10 @@
Совпадает с %1$sОчистить существующие совпаденияНе найдено.
- Искать в хранилище...Сохранение не удалось из-за внутренней ошибкиЭто приложение в настоящее время не поддерживаетсяПароли не совпадают
- Сгенерировать пароль...
- Извлечение кодов из SMS…
+ Извлечение кодов из SMSДостигнуто максимальное количество совпадений (%1$d); очистите совпадения перед тем как добавите новые.Издатель приложения изменился с тех пор как вы первый раз связали с ним запись хранилища паролей:Установленное приложение может попытаться украсть ваши учетные данные, выдавая себя за доверенное приложение\n\nПопробуйте удалить или переустановить приложение из доверенного источника, такого как Play Store, Amazon Appstore, F-Droid или магазин приложений производителя вашего смартфона.
@@ -205,7 +203,7 @@
Оставить автозаполнение отключеннымВключить автозаполнение сноваПредупреждение
- Нажмите для получения подробностей...
+ Нажмите для получения подробностейВозможная попытка фишингаЗаполнить и сохранить учетные данныеЗаполнить учетные данные
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ea222409..9c87c1da 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -231,16 +231,17 @@
App icon
+ Select entry to fill intoPhishing-resistant searchMatch with %1$sClear existing matchesNo results.
- Search in store…
+ Search entrySave failed due to an internal errorThis app is currently not supportedPasswords don\'t match
- Generate password…
- Extract code from SMS…
+ Create entry
+ Extract code from SMSMaximum number of matches (%1$d) reached; clear matches before adding new ones.This app\'s publisher has changed since you first associated a Password Store entry with it:The currently installed app may be trying to steal your credentials by pretending to be a trusted app.\n\nTry to uninstall and reinstall the app from a trusted source, such as the Play Store, Amazon Appstore, F-Droid, or your phone manufacturer\'s store.
@@ -250,7 +251,7 @@
Keep Autofill disabledRe-enable AutofillWarning
- Tap for details…
+ Tap for detailsPossible phishing attemptFill and save credentialsFill credentials
diff --git a/app/src/main/res/xml/oreo_autofill_service.xml b/app/src/main/res/xml/oreo_autofill_service.xml
index 00736cd5..b8a7510b 100644
--- a/app/src/main/res/xml/oreo_autofill_service.xml
+++ b/app/src/main/res/xml/oreo_autofill_service.xml
@@ -5,6 +5,7 @@