implement inline suggestions for autofill service on Android 11+, closes https://github.com/PhilippC/keepass2android/issues/1374 and https://github.com/PhilippC/keepass2android/issues/1534
This commit is contained in:
@@ -51,6 +51,7 @@
|
||||
<!-- Preference settings -->
|
||||
<string name="AutoReturnFromQuery_key">AutoReturnFromQuery_key</string>
|
||||
<string name="NoDalVerification_key">NoDalVerification_key</string>
|
||||
<string name="InlineSuggestions_key">InlineSuggestions_key</string>
|
||||
<string name="algorithm_key">algorithm</string>
|
||||
<string name="app_key">app</string>
|
||||
<string name="app_timeout_key">app_timeout_key</string>
|
||||
|
@@ -317,6 +317,10 @@
|
||||
<string name="RememberRecentFiles_summary">Remember recently opened databases and show them in the Open database screen.</string>
|
||||
<string name="NoDalVerification_title">No DAL verification</string>
|
||||
<string name="NoDalVerification_summary">Disables check if domain and app package match</string>
|
||||
|
||||
<string name="InlineSuggestions_title">Integrate with keyboard</string>
|
||||
<string name="InlineSuggestions_summary">Shows the autofill suggestions as inline options in the keyboard (if supported by the input method)</string>
|
||||
<string name="requires_android11">Requires Android 11 or later</string>
|
||||
|
||||
<string name="kp2a_findUrl">Find password</string>
|
||||
<string name="excludeExpiredEntries">Exclude expired entries</string>
|
||||
|
@@ -38,7 +38,7 @@
|
||||
<item name="android:textSize">12sp</item>
|
||||
</style>
|
||||
<style name="InfoHeader">
|
||||
<item name="android:drawableBottom">@drawable/section_header</item>
|
||||
<item name="android:drawableBottom">@drawable/section_header</item>
|
||||
<item name="android:drawablePadding">2dp</item>
|
||||
<item name="android:layout_marginLeft">0dip</item>
|
||||
<item name="android:layout_marginRight">12dip</item>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<autofill-service
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:supportsInlineSuggestions="true"
|
||||
>
|
||||
<compatibility-package
|
||||
android:name="com.android.chrome"
|
||||
|
@@ -404,11 +404,6 @@
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
<Preference android:title="@string/AccServiceAutoFill_prefs" >
|
||||
<intent android:action="android.intent.action.VIEW"
|
||||
android:data="https://philippc.github.io/keepass2android/AccServiceAutoFill.html" />
|
||||
</Preference>
|
||||
|
||||
<PreferenceScreen
|
||||
android:key="@string/AutoFill_prefs_screen_key"
|
||||
android:title="@string/AutoFill_prefs"
|
||||
@@ -439,6 +434,14 @@
|
||||
android:title="@string/NoDalVerification_title"
|
||||
android:key="@string/NoDalVerification_key" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:enabled="true"
|
||||
android:persistent="true"
|
||||
android:summary="@string/InlineSuggestions_summary"
|
||||
android:defaultValue="true"
|
||||
android:title="@string/InlineSuggestions_title"
|
||||
android:key="@string/InlineSuggestions_key" />
|
||||
|
||||
<keepass2android.AutofillDisabledQueriesPreference
|
||||
android:title="@string/AutofillDisabledQueriesPreference_title"
|
||||
android:summary="@string/AutofillDisabledQueriesPreference_summary"
|
||||
|
@@ -1,9 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Service.Autofill;
|
||||
using Android.Util;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Android.Widget.Inline;
|
||||
using AndroidX.AutoFill.Inline;
|
||||
using AndroidX.AutoFill.Inline.V1;
|
||||
using FilledAutofillFieldCollection = keepass2android.services.AutofillBase.model.FilledAutofillFieldCollection;
|
||||
|
||||
namespace keepass2android.services.AutofillBase
|
||||
@@ -13,43 +20,127 @@ namespace keepass2android.services.AutofillBase
|
||||
/// </summary>
|
||||
public class AutofillHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Wraps autofill data in a LoginCredential Dataset object which can then be sent back to the
|
||||
/// client View.
|
||||
/// </summary>
|
||||
/// <returns>The dataset.</returns>
|
||||
/// <param name="context">Context.</param>
|
||||
/// <param name="autofillFields">Autofill fields.</param>
|
||||
/// <param name="filledAutofillFieldCollection">Filled autofill field collection.</param>
|
||||
public static Dataset NewDataset(Context context,
|
||||
AutofillFieldMetadataCollection autofillFields, FilledAutofillFieldCollection filledAutofillFieldCollection, IAutofillIntentBuilder intentBuilder)
|
||||
{
|
||||
var datasetName = filledAutofillFieldCollection.DatasetName ?? "[noname]";
|
||||
|
||||
var datasetBuilder = new Dataset.Builder(NewRemoteViews(context.PackageName, datasetName, intentBuilder.AppIconResource));
|
||||
|
||||
public static InlinePresentation BuildInlinePresentation(InlinePresentationSpec inlinePresentationSpec,
|
||||
string text, string subtext, int iconId, PendingIntent pendingIntent, Context context)
|
||||
{
|
||||
if ((int)Build.VERSION.SdkInt < 30 || inlinePresentationSpec == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
//make sure we have a pendingIntent always not null
|
||||
pendingIntent ??= PendingIntent.GetService(context, 0, new Intent(),
|
||||
PendingIntentFlags.OneShot | PendingIntentFlags.UpdateCurrent);
|
||||
var slice = CreateInlinePresentationSlice(
|
||||
inlinePresentationSpec,
|
||||
text,
|
||||
subtext,
|
||||
iconId,
|
||||
"Autofill option",
|
||||
pendingIntent,
|
||||
context);
|
||||
if (slice != null)
|
||||
{
|
||||
return new InlinePresentation(slice, inlinePresentationSpec, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Android.App.Slices.Slice CreateInlinePresentationSlice(
|
||||
InlinePresentationSpec inlinePresentationSpec,
|
||||
string text,
|
||||
string subtext,
|
||||
int iconId,
|
||||
string contentDescription,
|
||||
PendingIntent pendingIntent,
|
||||
Context context)
|
||||
{
|
||||
var imeStyle = inlinePresentationSpec.Style;
|
||||
|
||||
if (!UiVersions.GetVersions(imeStyle).Contains(UiVersions.InlineUiVersion1))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var contentBuilder = InlineSuggestionUi.NewContentBuilder(pendingIntent)
|
||||
.SetContentDescription(contentDescription);
|
||||
if (!string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
contentBuilder.SetTitle(text);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(subtext))
|
||||
{
|
||||
contentBuilder.SetSubtitle(subtext);
|
||||
}
|
||||
if (iconId > 0)
|
||||
{
|
||||
var icon = Android.Graphics.Drawables.Icon.CreateWithResource(context, iconId);
|
||||
if (icon != null)
|
||||
{
|
||||
if (iconId == AppNames.LauncherIcon)
|
||||
{
|
||||
// Don't tint our logo
|
||||
icon.SetTintBlendMode(Android.Graphics.BlendMode.Dst);
|
||||
}
|
||||
contentBuilder.SetStartIcon(icon);
|
||||
}
|
||||
}
|
||||
return contentBuilder.Build().JavaCast<InlineSuggestionUi.Content>()?.Slice;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wraps autofill data in a LoginCredential Dataset object which can then be sent back to the
|
||||
/// client View.
|
||||
/// </summary>
|
||||
/// <returns>The dataset.</returns>
|
||||
/// <param name="context">Context.</param>
|
||||
/// <param name="autofillFields">Autofill fields.</param>
|
||||
/// <param name="filledAutofillFieldCollection">Filled autofill field collection.</param>
|
||||
public static Dataset NewDataset(Context context,
|
||||
AutofillFieldMetadataCollection autofillFields,
|
||||
FilledAutofillFieldCollection filledAutofillFieldCollection,
|
||||
IAutofillIntentBuilder intentBuilder,
|
||||
Android.Widget.Inline.InlinePresentationSpec inlinePresentationSpec)
|
||||
{
|
||||
var datasetName = filledAutofillFieldCollection.DatasetName ?? "[noname]";
|
||||
|
||||
var datasetBuilder = new Dataset.Builder(NewRemoteViews(context.PackageName, datasetName, intentBuilder.AppIconResource));
|
||||
datasetBuilder.SetId(datasetName);
|
||||
|
||||
var setValueAtLeastOnce = filledAutofillFieldCollection.ApplyToFields(autofillFields, datasetBuilder);
|
||||
|
||||
var setValueAtLeastOnce = filledAutofillFieldCollection.ApplyToFields(autofillFields, datasetBuilder);
|
||||
AddInlinePresentation(context, inlinePresentationSpec, datasetName, datasetBuilder, intentBuilder.AppIconResource);
|
||||
|
||||
if (setValueAtLeastOnce)
|
||||
{
|
||||
return datasetBuilder.Build();
|
||||
}
|
||||
if (setValueAtLeastOnce)
|
||||
{
|
||||
return datasetBuilder.Build();
|
||||
}
|
||||
else
|
||||
{
|
||||
Kp2aLog.Log("Failed to set at least one value. #fields="+autofillFields.GetAutofillIds().Length + " " + autofillFields.FocusedAutofillCanonicalHints);
|
||||
Kp2aLog.Log("Failed to set at least one value. #fields=" + autofillFields.GetAutofillIds().Length + " " + autofillFields.FocusedAutofillCanonicalHints);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static RemoteViews NewRemoteViews(string packageName, string remoteViewsText,int drawableId)
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void AddInlinePresentation(Context context, InlinePresentationSpec inlinePresentationSpec, string datasetName, Dataset.Builder datasetBuilder, int iconId)
|
||||
{
|
||||
if (inlinePresentationSpec != null)
|
||||
{
|
||||
var inlinePresentation = BuildInlinePresentation(inlinePresentationSpec, datasetName, "", iconId, null, context);
|
||||
datasetBuilder.SetInlinePresentation(inlinePresentation);
|
||||
}
|
||||
}
|
||||
|
||||
public static RemoteViews NewRemoteViews(string packageName, string remoteViewsText,int drawableId)
|
||||
{
|
||||
RemoteViews presentation = new RemoteViews(packageName, Resource.Layout.autofill_service_list_item);
|
||||
presentation.SetTextViewText(Resource.Id.text, remoteViewsText);
|
||||
presentation.SetImageViewResource(Resource.Id.icon, drawableId);
|
||||
return presentation;
|
||||
}
|
||||
}
|
||||
|
||||
internal static InlinePresentationSpec ExtractSpec(IList<InlinePresentationSpec> inlinePresentationSpecs, int index)
|
||||
{
|
||||
return inlinePresentationSpecs == null ? null : inlinePresentationSpecs[Math.Min(index, inlinePresentationSpecs.Count - 1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,15 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Android.App;
|
||||
using Android.App.Slices;
|
||||
using Android.Content;
|
||||
using Android.Content.PM;
|
||||
using Android.Graphics;
|
||||
using Android.Graphics.Drawables;
|
||||
using Android.OS;
|
||||
using Android.Preferences;
|
||||
using Android.Runtime;
|
||||
using Android.Service.Autofill;
|
||||
using Android.Util;
|
||||
using Android.Views.Autofill;
|
||||
using Android.Views.InputMethods;
|
||||
using Android.Widget;
|
||||
using Android.Widget.Inline;
|
||||
using AndroidX.AutoFill.Inline;
|
||||
using AndroidX.AutoFill.Inline.V1;
|
||||
using Java.Util.Concurrent.Atomic;
|
||||
using keepass2android.services.AutofillBase.model;
|
||||
|
||||
@@ -125,6 +133,15 @@ namespace keepass2android.services.AutofillBase
|
||||
}
|
||||
|
||||
AutofillFieldMetadataCollection autofillFields = parser.AutofillFields;
|
||||
InlineSuggestionsRequest inlineSuggestionsRequest = null;
|
||||
IList<InlinePresentationSpec> inlinePresentationSpecs = null;
|
||||
if (((int) Build.VERSION.SdkInt >= 30)
|
||||
&& (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(GetString(Resource.String.InlineSuggestions_key), true)))
|
||||
{
|
||||
inlineSuggestionsRequest = request.InlineSuggestionsRequest;
|
||||
|
||||
inlinePresentationSpecs = inlineSuggestionsRequest?.InlinePresentationSpecs;
|
||||
}
|
||||
|
||||
|
||||
var autofillIds = autofillFields.GetAutofillIds();
|
||||
@@ -134,13 +151,27 @@ namespace keepass2android.services.AutofillBase
|
||||
|
||||
bool hasEntryDataset = false;
|
||||
|
||||
IList<Dataset> entryDatasets = new List<Dataset>();
|
||||
if (query.IncompatiblePackageAndDomain == false)
|
||||
{
|
||||
Kp2aLog.Log("AF: (query.IncompatiblePackageAndDomain == false)");
|
||||
//domain and package are compatible. Use Domain if available and package otherwise. Can fill without warning.
|
||||
foreach (var entryDataset in BuildEntryDatasets(query.DomainOrPackage, query.WebDomain,
|
||||
query.PackageName,
|
||||
autofillIds, parser, DisplayWarning.None).Where(ds => ds != null)
|
||||
entryDatasets = BuildEntryDatasets(query.DomainOrPackage, query.WebDomain,
|
||||
query.PackageName,
|
||||
autofillIds, parser, DisplayWarning.None,
|
||||
inlinePresentationSpecs
|
||||
).Where(ds => ds != null).ToList();
|
||||
if (entryDatasets.Count > inlineSuggestionsRequest?.MaxSuggestionCount - 2 /*disable dataset and query*/)
|
||||
{
|
||||
//we have too many elements. disable inline suggestions
|
||||
inlinePresentationSpecs = null;
|
||||
entryDatasets = BuildEntryDatasets(query.DomainOrPackage, query.WebDomain,
|
||||
query.PackageName,
|
||||
autofillIds, parser, DisplayWarning.None,
|
||||
null
|
||||
).Where(ds => ds != null).ToList();
|
||||
}
|
||||
foreach (var entryDataset in entryDatasets
|
||||
)
|
||||
{
|
||||
Kp2aLog.Log("AF: Got EntryDataset " + (entryDataset == null));
|
||||
@@ -158,14 +189,16 @@ namespace keepass2android.services.AutofillBase
|
||||
isManual, autofillIds, responseBuilder, !hasEntryDataset,
|
||||
query.IncompatiblePackageAndDomain
|
||||
? DisplayWarning.FillDomainInUntrustedApp
|
||||
: DisplayWarning.None);
|
||||
: DisplayWarning.None,
|
||||
AutofillHelper.ExtractSpec(inlinePresentationSpecs, entryDatasets.Count));
|
||||
else
|
||||
AddQueryDataset(query.PackageNameWithPseudoSchema,
|
||||
query.WebDomain, query.PackageName,
|
||||
isManual, autofillIds, responseBuilder, !hasEntryDataset, DisplayWarning.None);
|
||||
isManual, autofillIds, responseBuilder, !hasEntryDataset, DisplayWarning.None,
|
||||
AutofillHelper.ExtractSpec(inlinePresentationSpecs, entryDatasets.Count));
|
||||
}
|
||||
|
||||
AddDisableDataset(query.DomainOrPackage, autofillIds, responseBuilder, isManual);
|
||||
AddDisableDataset(query.DomainOrPackage, autofillIds, responseBuilder, isManual, AutofillHelper.ExtractSpec(inlinePresentationSpecs, entryDatasets.Count));
|
||||
|
||||
if (PreferenceManager.GetDefaultSharedPreferences(this)
|
||||
.GetBoolean(GetString(Resource.String.OfferSaveCredentials_key), true))
|
||||
@@ -192,20 +225,26 @@ namespace keepass2android.services.AutofillBase
|
||||
Kp2aLog.Log("Ignoring onFillRequest as there is another request going on.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private List<Dataset> BuildEntryDatasets(string query, string queryDomain, string queryPackage, AutofillId[] autofillIds, StructureParser parser,
|
||||
DisplayWarning warning)
|
||||
DisplayWarning warning, IList<InlinePresentationSpec> inlinePresentationSpecs)
|
||||
{
|
||||
List<Dataset> result = new List<Dataset>();
|
||||
Kp2aLog.Log("AF: BuildEntryDatasets");
|
||||
var suggestedEntries = GetSuggestedEntries(query).ToDictionary(e => e.DatasetName, e => e);
|
||||
Kp2aLog.Log("AF: BuildEntryDatasets found " + suggestedEntries.Count + " entries");
|
||||
int count = 0;
|
||||
foreach (var filledAutofillFieldCollection in suggestedEntries.Values)
|
||||
{
|
||||
|
||||
if (filledAutofillFieldCollection == null)
|
||||
continue;
|
||||
|
||||
var inlinePresentationSpec = AutofillHelper.ExtractSpec(inlinePresentationSpecs, count);
|
||||
|
||||
if (warning == DisplayWarning.None)
|
||||
{
|
||||
|
||||
@@ -214,12 +253,13 @@ namespace keepass2android.services.AutofillBase
|
||||
|
||||
Kp2aLog.Log("AF: Add dataset");
|
||||
|
||||
result.Add(AutofillHelper.NewDataset(this, parser.AutofillFields, partitionData, IntentBuilder));
|
||||
result.Add(AutofillHelper.NewDataset(this, parser.AutofillFields, partitionData, IntentBuilder,
|
||||
inlinePresentationSpec));
|
||||
}
|
||||
else
|
||||
{
|
||||
//return an "auth" dataset (actually for just warning the user in case domain/package dont match)
|
||||
var sender =
|
||||
IntentSender sender =
|
||||
IntentBuilder.GetAuthIntentSenderForWarning(this, query, queryDomain, queryPackage, warning);
|
||||
var datasetName = filledAutofillFieldCollection.DatasetName;
|
||||
if (datasetName == null)
|
||||
@@ -233,6 +273,9 @@ namespace keepass2android.services.AutofillBase
|
||||
|
||||
var datasetBuilder = new Dataset.Builder(presentation);
|
||||
datasetBuilder.SetAuthentication(sender);
|
||||
|
||||
AutofillHelper.AddInlinePresentation(this, inlinePresentationSpec, datasetName, datasetBuilder, AppNames.LauncherIcon);
|
||||
|
||||
//need to add placeholders so we can directly fill after ChooseActivity
|
||||
foreach (var autofillId in autofillIds)
|
||||
{
|
||||
@@ -241,6 +284,7 @@ namespace keepass2android.services.AutofillBase
|
||||
Kp2aLog.Log("AF: Add auth dataset");
|
||||
result.Add(datasetBuilder.Build());
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -257,11 +301,12 @@ namespace keepass2android.services.AutofillBase
|
||||
|
||||
}
|
||||
|
||||
private void AddQueryDataset(string query, string queryDomain, string queryPackage, bool isManual, AutofillId[] autofillIds, FillResponse.Builder responseBuilder, bool autoReturnFromQuery, DisplayWarning warning)
|
||||
private void AddQueryDataset(string query, string queryDomain, string queryPackage, bool isManual, AutofillId[] autofillIds, FillResponse.Builder responseBuilder, bool autoReturnFromQuery, DisplayWarning warning, InlinePresentationSpec inlinePresentationSpec)
|
||||
{
|
||||
var sender = IntentBuilder.GetAuthIntentSenderForResponse(this, query, queryDomain, queryPackage, isManual, autoReturnFromQuery, warning);
|
||||
RemoteViews presentation = AutofillHelper.NewRemoteViews(PackageName,
|
||||
GetString(Resource.String.autofill_sign_in_prompt), AppNames.LauncherIcon);
|
||||
string text = GetString(Resource.String.autofill_sign_in_prompt);
|
||||
RemoteViews presentation = AutofillHelper.NewRemoteViews(base.PackageName,
|
||||
text, AppNames.LauncherIcon);
|
||||
|
||||
var datasetBuilder = new Dataset.Builder(presentation);
|
||||
datasetBuilder.SetAuthentication(sender);
|
||||
@@ -271,6 +316,9 @@ namespace keepass2android.services.AutofillBase
|
||||
datasetBuilder.SetValue(autofillId, AutofillValue.ForText("PLACEHOLDER"));
|
||||
}
|
||||
|
||||
AutofillHelper.AddInlinePresentation(this, inlinePresentationSpec, text, datasetBuilder, AppNames.LauncherIcon);
|
||||
|
||||
|
||||
responseBuilder.AddDataset(datasetBuilder.Build());
|
||||
}
|
||||
public static string GetDisplayNameForQuery(string str, Context Context)
|
||||
@@ -303,20 +351,23 @@ namespace keepass2android.services.AutofillBase
|
||||
return displayName;
|
||||
}
|
||||
|
||||
private void AddDisableDataset(string query, AutofillId[] autofillIds, FillResponse.Builder responseBuilder, bool isManual)
|
||||
private void AddDisableDataset(string query, AutofillId[] autofillIds, FillResponse.Builder responseBuilder, bool isManual, InlinePresentationSpec inlinePresentationSpec)
|
||||
{
|
||||
bool isQueryDisabled = IsQueryDisabled(query);
|
||||
if (isQueryDisabled && !isManual)
|
||||
return;
|
||||
bool isForDisable = !isQueryDisabled;
|
||||
var sender = IntentBuilder.GetDisableIntentSenderForResponse(this, query, isManual, isForDisable);
|
||||
|
||||
RemoteViews presentation = AutofillHelper.NewRemoteViews(PackageName,
|
||||
GetString(isForDisable ? Resource.String.autofill_disable : Resource.String.autofill_enable_for, new Java.Lang.Object[] { GetDisplayNameForQuery(query, this)}), Resource.Drawable.ic_menu_close_grey);
|
||||
|
||||
string text = GetString(isForDisable ? Resource.String.autofill_disable : Resource.String.autofill_enable_for, new Java.Lang.Object[] { GetDisplayNameForQuery(query, this) });
|
||||
RemoteViews presentation = AutofillHelper.NewRemoteViews(base.PackageName,
|
||||
text, Resource.Drawable.ic_menu_close_grey);
|
||||
|
||||
var datasetBuilder = new Dataset.Builder(presentation);
|
||||
datasetBuilder.SetAuthentication(sender);
|
||||
|
||||
AutofillHelper.AddInlinePresentation(this, inlinePresentationSpec, text, datasetBuilder, Resource.Drawable.ic_menu_close_grey);
|
||||
|
||||
foreach (var autofillId in autofillIds)
|
||||
{
|
||||
datasetBuilder.SetValue(autofillId, AutofillValue.ForText("PLACEHOLDER"));
|
||||
|
@@ -183,7 +183,7 @@ namespace keepass2android.services.AutofillBase
|
||||
|
||||
|
||||
ReplyIntent = new Intent();
|
||||
SetDatasetIntent(AutofillHelper.NewDataset(this, autofillFields, partitionData, IntentBuilder));
|
||||
SetDatasetIntent(AutofillHelper.NewDataset(this, autofillFields, partitionData, IntentBuilder, null /*TODO can we get the inlinePresentationSpec here?*/));
|
||||
SetResult(Result.Ok, ReplyIntent);
|
||||
}
|
||||
|
||||
|
@@ -320,6 +320,8 @@ namespace keepass2android
|
||||
var autofillPref = FindPreference(GetString(Resource.String.AutoFill_prefs_key));
|
||||
var autofillDisabledPref = FindPreference(GetString(Resource.String.AutofillDisabledQueriesPreference_key));
|
||||
var autofillSavePref = FindPreference(GetString(Resource.String.OfferSaveCredentials_key));
|
||||
var autofillInlineSuggestions = FindPreference(GetString(Resource.String.InlineSuggestions_key));
|
||||
var autofillNoDalVerification = FindPreference(GetString(Resource.String.NoDalVerification_key));
|
||||
if (autofillPref == null)
|
||||
return;
|
||||
if ((Android.OS.Build.VERSION.SdkInt < Android.OS.BuildVersionCodes.O) ||
|
||||
@@ -337,17 +339,25 @@ namespace keepass2android
|
||||
{
|
||||
autofillDisabledPref.Enabled = true;
|
||||
autofillSavePref.Enabled = true;
|
||||
autofillNoDalVerification.Enabled = true;
|
||||
autofillInlineSuggestions.Enabled = true;
|
||||
autofillPref.Summary = Activity.GetString(Resource.String.plugin_enabled);
|
||||
autofillPref.Intent = new Intent(Intent.ActionView);
|
||||
autofillPref.Intent.SetData(Android.Net.Uri.Parse("https://philippc.github.io/keepass2android/OreoAutoFill.html"));
|
||||
}
|
||||
else
|
||||
{
|
||||
autofillNoDalVerification.Enabled = false;
|
||||
autofillDisabledPref.Enabled = false;
|
||||
autofillSavePref.Enabled = false;
|
||||
autofillInlineSuggestions.Enabled = false;
|
||||
autofillPref.Summary = Activity.GetString(Resource.String.not_enabled);
|
||||
}
|
||||
if ((int)Android.OS.Build.VERSION.SdkInt < 30)
|
||||
{
|
||||
autofillInlineSuggestions.Summary = Activity.GetString(Resource.String.requires_android11);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user