allow autofill (#9) for apps/websites without explicit autofill hints by detecting password fields and falling back to filling username/password if no autofill hint is available
This commit is contained in:
@@ -22,13 +22,20 @@ namespace keepass2android.services.AutofillBase
|
||||
string[] AutofillOptions { get; }
|
||||
public bool Focused { get; }
|
||||
|
||||
public AutofillFieldMetadata(AssistStructure.ViewNode view)
|
||||
public AutofillFieldMetadata(AssistStructure.ViewNode view)
|
||||
: this(view, view.GetAutofillHints())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public AutofillFieldMetadata(AssistStructure.ViewNode view, string[] autofillHints)
|
||||
{
|
||||
AutofillId = view.AutofillId;
|
||||
AutofillType = view.AutofillType;
|
||||
AutofillOptions = view.GetAutofillOptions();
|
||||
Focused = view.IsFocused;
|
||||
var supportedHints = AutofillHintsHelper.FilterForSupportedHints(view.GetAutofillHints());
|
||||
var supportedHints = AutofillHintsHelper.FilterForSupportedHints(autofillHints);
|
||||
var canonicalHints = AutofillHintsHelper.ConvertToCanonicalHints(supportedHints);
|
||||
SetHints(canonicalHints.ToArray());
|
||||
|
||||
|
||||
@@ -20,7 +20,12 @@ namespace keepass2android.services.AutofillBase
|
||||
int Size = 0;
|
||||
public SaveDataType SaveType { get; set; }
|
||||
|
||||
public AutofillFieldMetadataCollection()
|
||||
public bool Empty
|
||||
{
|
||||
get { return Size == 0; }
|
||||
}
|
||||
|
||||
public AutofillFieldMetadataCollection()
|
||||
{
|
||||
SaveType = 0;
|
||||
FocusedAutofillCanonicalHints = new List<string>();
|
||||
|
||||
@@ -31,13 +31,13 @@ namespace keepass2android.services.AutofillBase
|
||||
|
||||
public override void OnFillRequest(FillRequest request, CancellationSignal cancellationSignal, FillCallback callback)
|
||||
{
|
||||
Log.Debug(CommonUtil.Tag, "onFillRequest");
|
||||
CommonUtil.logd( "onFillRequest");
|
||||
var structure = request.FillContexts[request.FillContexts.Count - 1].Structure;
|
||||
|
||||
//TODO package signature verification?
|
||||
|
||||
var clientState = request.ClientState;
|
||||
Log.Debug(CommonUtil.Tag, "onFillRequest(): data=" + CommonUtil.BundleToString(clientState));
|
||||
CommonUtil.logd( "onFillRequest(): data=" + CommonUtil.BundleToString(clientState));
|
||||
|
||||
|
||||
cancellationSignal.CancelEvent += (sender, e) => {
|
||||
@@ -62,7 +62,7 @@ namespace keepass2android.services.AutofillBase
|
||||
|
||||
bool responseAuth = true;
|
||||
var autofillIds = autofillFields.GetAutofillIds();
|
||||
if (responseAuth && autofillIds.Length != 0)
|
||||
if (responseAuth && autofillIds.Length != 0 && CanAutofill(query))
|
||||
{
|
||||
var responseBuilder = new FillResponse.Builder();
|
||||
|
||||
@@ -89,6 +89,11 @@ namespace keepass2android.services.AutofillBase
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanAutofill(string query)
|
||||
{
|
||||
return !(query == "androidapp://android" || query == "androidapp://"+this.PackageName);
|
||||
}
|
||||
|
||||
public override void OnSaveRequest(SaveRequest request, SaveCallback callback)
|
||||
{
|
||||
//TODO implement
|
||||
@@ -98,12 +103,12 @@ namespace keepass2android.services.AutofillBase
|
||||
|
||||
public override void OnConnected()
|
||||
{
|
||||
Log.Debug(CommonUtil.Tag, "onConnected");
|
||||
CommonUtil.logd( "onConnected");
|
||||
}
|
||||
|
||||
public override void OnDisconnected()
|
||||
{
|
||||
Log.Debug(CommonUtil.Tag, "onDisconnected");
|
||||
CommonUtil.logd( "onDisconnected");
|
||||
}
|
||||
|
||||
public abstract IAutofillIntentBuilder IntentBuilder{get;}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Android.App.Assist;
|
||||
using Android.Content;
|
||||
using Android.Text;
|
||||
using Android.Util;
|
||||
using Android.Views;
|
||||
using FilledAutofillFieldCollection = keepass2android.services.AutofillBase.model.FilledAutofillFieldCollection;
|
||||
|
||||
namespace keepass2android.services.AutofillBase
|
||||
@@ -16,7 +20,8 @@ namespace keepass2android.services.AutofillBase
|
||||
public Context mContext { get; }
|
||||
public AutofillFieldMetadataCollection AutofillFields { get; set; }
|
||||
AssistStructure Structure;
|
||||
public FilledAutofillFieldCollection ClientFormData { get; set; }
|
||||
private List<AssistStructure.ViewNode> _editTextsWithoutHint = new List<AssistStructure.ViewNode>();
|
||||
public FilledAutofillFieldCollection ClientFormData { get; set; }
|
||||
|
||||
public StructureParser(Context context, AssistStructure structure)
|
||||
{
|
||||
@@ -46,12 +51,52 @@ namespace keepass2android.services.AutofillBase
|
||||
var nodes = Structure.WindowNodeCount;
|
||||
ClientFormData = new FilledAutofillFieldCollection();
|
||||
String webDomain = null;
|
||||
for (int i = 0; i < nodes; i++)
|
||||
_editTextsWithoutHint.Clear();
|
||||
|
||||
for (int i = 0; i < nodes; i++)
|
||||
{
|
||||
var node = Structure.GetWindowNodeAt(i);
|
||||
var view = node.RootViewNode;
|
||||
ParseLocked(forFill, view, ref webDomain);
|
||||
}
|
||||
|
||||
if (AutofillFields.Empty)
|
||||
{
|
||||
var passwordFields = _editTextsWithoutHint
|
||||
.Where(f =>
|
||||
(!f.IdEntry?.ToLowerInvariant().Contains("search") ?? true) &&
|
||||
(!f.Hint?.ToLowerInvariant().Contains("search") ?? true) &&
|
||||
(
|
||||
f.InputType.HasFlag(InputTypes.TextVariationPassword) ||
|
||||
f.InputType.HasFlag(InputTypes.TextVariationVisiblePassword) ||
|
||||
f.InputType.HasFlag(InputTypes.TextVariationWebPassword) ||
|
||||
(f.HtmlInfo?.Attributes.Any(p => p.First.ToString() == "type" && p.Second.ToString() == "password") ?? false)
|
||||
)
|
||||
).ToList();
|
||||
if (!_editTextsWithoutHint.Any())
|
||||
{
|
||||
passwordFields = _editTextsWithoutHint.Where(f =>
|
||||
(f.IdEntry?.ToLowerInvariant().Contains("password") ?? false)
|
||||
|| (f.Hint?.ToLowerInvariant().Contains("password") ?? false)).ToList();
|
||||
|
||||
|
||||
}
|
||||
foreach (var passwordField in passwordFields)
|
||||
{
|
||||
AutofillFields.Add(new AutofillFieldMetadata(passwordField, new[] { View.AutofillHintPassword }));
|
||||
var usernameField = _editTextsWithoutHint.TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault();
|
||||
if (usernameField != null)
|
||||
{
|
||||
AutofillFields.Add(new AutofillFieldMetadata(usernameField, new[] {View.AutofillHintUsername}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
String packageName = Structure.ActivityComponent.PackageName;
|
||||
if (!string.IsNullOrEmpty(webDomain))
|
||||
{
|
||||
@@ -103,6 +148,10 @@ namespace keepass2android.services.AutofillBase
|
||||
//ClientFormData.Add(new FilledAutofillField(viewNode));
|
||||
}
|
||||
}
|
||||
else if (viewNode.ClassName == "android.widget.EditText" || viewNode?.HtmlInfo?.Tag == "input")
|
||||
{
|
||||
_editTextsWithoutHint.Add(viewNode);
|
||||
}
|
||||
var childrenSize = viewNode.ChildCount;
|
||||
if (childrenSize > 0)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user