improve implementation of Oreo autofill (#9), now supporting all Android/W3cHints, using all Keepass fields (if hints match field name). Make hint comparison code clearer and always compare case insensitive
This commit is contained in:
@@ -14,8 +14,8 @@ namespace keepass2android.services.AutofillBase
|
|||||||
public class AutofillFieldMetadata
|
public class AutofillFieldMetadata
|
||||||
{
|
{
|
||||||
public SaveDataType SaveType { get; set; }
|
public SaveDataType SaveType { get; set; }
|
||||||
|
|
||||||
public string[] AutofillHints { get; set; }
|
public string[] AutofillCanonicalHints { get; set; }
|
||||||
|
|
||||||
public AutofillId AutofillId { get; }
|
public AutofillId AutofillId { get; }
|
||||||
public AutofillType AutofillType { get; }
|
public AutofillType AutofillType { get; }
|
||||||
@@ -29,14 +29,14 @@ namespace keepass2android.services.AutofillBase
|
|||||||
AutofillOptions = view.GetAutofillOptions();
|
AutofillOptions = view.GetAutofillOptions();
|
||||||
Focused = view.IsFocused;
|
Focused = view.IsFocused;
|
||||||
var supportedHints = AutofillHintsHelper.FilterForSupportedHints(view.GetAutofillHints());
|
var supportedHints = AutofillHintsHelper.FilterForSupportedHints(view.GetAutofillHints());
|
||||||
var storedHints = AutofillHintsHelper.ConvertToStoredHints(supportedHints);
|
var canonicalHints = AutofillHintsHelper.ConvertToCanonicalHints(supportedHints);
|
||||||
SetHints(storedHints.ToArray());
|
SetHints(canonicalHints.ToArray());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetHints(string[] value)
|
void SetHints(string[] value)
|
||||||
{
|
{
|
||||||
AutofillHints = value;
|
AutofillCanonicalHints = value;
|
||||||
UpdateSaveTypeFromHints();
|
UpdateSaveTypeFromHints();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,11 +62,11 @@ namespace keepass2android.services.AutofillBase
|
|||||||
{
|
{
|
||||||
//TODO future add savetypes for W3cHints
|
//TODO future add savetypes for W3cHints
|
||||||
SaveType = 0;
|
SaveType = 0;
|
||||||
if (AutofillHints == null)
|
if (AutofillCanonicalHints == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach (var hint in AutofillHints)
|
foreach (var hint in AutofillCanonicalHints)
|
||||||
{
|
{
|
||||||
switch (hint)
|
switch (hint)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,17 +12,19 @@ namespace keepass2android.services.AutofillBase
|
|||||||
public class AutofillFieldMetadataCollection
|
public class AutofillFieldMetadataCollection
|
||||||
{
|
{
|
||||||
List<AutofillId> AutofillIds = new List<AutofillId>();
|
List<AutofillId> AutofillIds = new List<AutofillId>();
|
||||||
Dictionary<string, List<AutofillFieldMetadata>> AutofillHintsToFieldsMap = new Dictionary<string, List<AutofillFieldMetadata>>();
|
|
||||||
public List<string> AllAutofillHints { get; }
|
Dictionary<string, List<AutofillFieldMetadata>> AutofillCanonicalHintsToFieldsMap = new Dictionary<string, List<AutofillFieldMetadata>>();
|
||||||
public List<string> FocusedAutofillHints { get; }
|
|
||||||
|
public List<string> AllAutofillCanonicalHints { get; }
|
||||||
|
public List<string> FocusedAutofillCanonicalHints { get; }
|
||||||
int Size = 0;
|
int Size = 0;
|
||||||
public SaveDataType SaveType { get; set; }
|
public SaveDataType SaveType { get; set; }
|
||||||
|
|
||||||
public AutofillFieldMetadataCollection()
|
public AutofillFieldMetadataCollection()
|
||||||
{
|
{
|
||||||
SaveType = 0;
|
SaveType = 0;
|
||||||
FocusedAutofillHints = new List<string>();
|
FocusedAutofillCanonicalHints = new List<string>();
|
||||||
AllAutofillHints = new List<string>();
|
AllAutofillCanonicalHints = new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(AutofillFieldMetadata autofillFieldMetadata)
|
public void Add(AutofillFieldMetadata autofillFieldMetadata)
|
||||||
@@ -30,19 +32,19 @@ namespace keepass2android.services.AutofillBase
|
|||||||
SaveType |= autofillFieldMetadata.SaveType;
|
SaveType |= autofillFieldMetadata.SaveType;
|
||||||
Size++;
|
Size++;
|
||||||
AutofillIds.Add(autofillFieldMetadata.AutofillId);
|
AutofillIds.Add(autofillFieldMetadata.AutofillId);
|
||||||
var hintsList = autofillFieldMetadata.AutofillHints;
|
var hintsList = autofillFieldMetadata.AutofillCanonicalHints;
|
||||||
AllAutofillHints.AddRange(hintsList);
|
AllAutofillCanonicalHints.AddRange(hintsList);
|
||||||
if (autofillFieldMetadata.Focused)
|
if (autofillFieldMetadata.Focused)
|
||||||
{
|
{
|
||||||
FocusedAutofillHints.AddRange(hintsList);
|
FocusedAutofillCanonicalHints.AddRange(hintsList);
|
||||||
}
|
}
|
||||||
foreach (var hint in autofillFieldMetadata.AutofillHints)
|
foreach (var hint in autofillFieldMetadata.AutofillCanonicalHints)
|
||||||
{
|
{
|
||||||
if (!AutofillHintsToFieldsMap.ContainsKey(hint))
|
if (!AutofillCanonicalHintsToFieldsMap.ContainsKey(hint))
|
||||||
{
|
{
|
||||||
AutofillHintsToFieldsMap.Add(hint, new List<AutofillFieldMetadata>());
|
AutofillCanonicalHintsToFieldsMap.Add(hint, new List<AutofillFieldMetadata>());
|
||||||
}
|
}
|
||||||
AutofillHintsToFieldsMap[hint].Add(autofillFieldMetadata);
|
AutofillCanonicalHintsToFieldsMap[hint].Add(autofillFieldMetadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,9 +53,17 @@ namespace keepass2android.services.AutofillBase
|
|||||||
return AutofillIds.ToArray();
|
return AutofillIds.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<AutofillFieldMetadata> GetFieldsForHint(String hint)
|
/// <summary>
|
||||||
|
/// returns the fields for the given hint or an empty list.
|
||||||
|
/// </summary>
|
||||||
|
public List<AutofillFieldMetadata> GetFieldsForHint(String canonicalHint)
|
||||||
{
|
{
|
||||||
return AutofillHintsToFieldsMap[hint];
|
List<AutofillFieldMetadata> result;
|
||||||
|
if (!AutofillCanonicalHintsToFieldsMap.TryGetValue(canonicalHint, out result))
|
||||||
|
{
|
||||||
|
result = new List<AutofillFieldMetadata>();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,16 +16,76 @@ namespace keepass2android.services.AutofillBase
|
|||||||
{
|
{
|
||||||
class AutofillHintsHelper
|
class AutofillHintsHelper
|
||||||
{
|
{
|
||||||
private static readonly HashSet<string> validHints = new HashSet<string>()
|
private static readonly HashSet<string> _allSupportedHints = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||||
{
|
{
|
||||||
View.AutofillHintUsername,
|
View.AutofillHintCreditCardExpirationDate,
|
||||||
|
View.AutofillHintCreditCardExpirationDay,
|
||||||
|
View.AutofillHintCreditCardExpirationMonth,
|
||||||
|
View.AutofillHintCreditCardExpirationYear,
|
||||||
|
View.AutofillHintCreditCardNumber,
|
||||||
|
View.AutofillHintCreditCardSecurityCode,
|
||||||
|
View.AutofillHintEmailAddress,
|
||||||
|
View.AutofillHintPhone,
|
||||||
|
View.AutofillHintName,
|
||||||
View.AutofillHintPassword,
|
View.AutofillHintPassword,
|
||||||
|
View.AutofillHintPostalAddress,
|
||||||
|
View.AutofillHintPostalCode,
|
||||||
|
View.AutofillHintUsername,
|
||||||
|
W3cHints.HONORIFIC_PREFIX,
|
||||||
|
W3cHints.NAME,
|
||||||
|
W3cHints.GIVEN_NAME,
|
||||||
|
W3cHints.ADDITIONAL_NAME,
|
||||||
|
W3cHints.FAMILY_NAME,
|
||||||
|
W3cHints.HONORIFIC_SUFFIX,
|
||||||
W3cHints.USERNAME,
|
W3cHints.USERNAME,
|
||||||
|
W3cHints.NEW_PASSWORD,
|
||||||
W3cHints.CURRENT_PASSWORD,
|
W3cHints.CURRENT_PASSWORD,
|
||||||
W3cHints.NEW_PASSWORD
|
W3cHints.ORGANIZATION_TITLE,
|
||||||
|
W3cHints.ORGANIZATION,
|
||||||
|
W3cHints.STREET_ADDRESS,
|
||||||
|
W3cHints.ADDRESS_LINE1,
|
||||||
|
W3cHints.ADDRESS_LINE2,
|
||||||
|
W3cHints.ADDRESS_LINE3,
|
||||||
|
W3cHints.ADDRESS_LEVEL4,
|
||||||
|
W3cHints.ADDRESS_LEVEL3,
|
||||||
|
W3cHints.ADDRESS_LEVEL2,
|
||||||
|
W3cHints.ADDRESS_LEVEL1,
|
||||||
|
W3cHints.COUNTRY,
|
||||||
|
W3cHints.COUNTRY_NAME,
|
||||||
|
W3cHints.POSTAL_CODE,
|
||||||
|
W3cHints.CC_NAME,
|
||||||
|
W3cHints.CC_GIVEN_NAME,
|
||||||
|
W3cHints.CC_ADDITIONAL_NAME,
|
||||||
|
W3cHints.CC_FAMILY_NAME,
|
||||||
|
W3cHints.CC_NUMBER,
|
||||||
|
W3cHints.CC_EXPIRATION,
|
||||||
|
W3cHints.CC_EXPIRATION_MONTH,
|
||||||
|
W3cHints.CC_EXPIRATION_YEAR,
|
||||||
|
W3cHints.CC_CSC,
|
||||||
|
W3cHints.CC_TYPE,
|
||||||
|
W3cHints.TRANSACTION_CURRENCY,
|
||||||
|
W3cHints.TRANSACTION_AMOUNT,
|
||||||
|
W3cHints.LANGUAGE,
|
||||||
|
W3cHints.BDAY,
|
||||||
|
W3cHints.BDAY_DAY,
|
||||||
|
W3cHints.BDAY_MONTH,
|
||||||
|
W3cHints.BDAY_YEAR,
|
||||||
|
W3cHints.SEX,
|
||||||
|
W3cHints.URL,
|
||||||
|
W3cHints.PHOTO,
|
||||||
|
W3cHints.TEL,
|
||||||
|
W3cHints.TEL_COUNTRY_CODE,
|
||||||
|
W3cHints.TEL_NATIONAL,
|
||||||
|
W3cHints.TEL_AREA_CODE,
|
||||||
|
W3cHints.TEL_LOCAL,
|
||||||
|
W3cHints.TEL_LOCAL_PREFIX,
|
||||||
|
W3cHints.TEL_LOCAL_SUFFIX,
|
||||||
|
W3cHints.TEL_EXTENSION,
|
||||||
|
W3cHints.EMAIL,
|
||||||
|
W3cHints.IMPP,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly Dictionary<string, string> hintReplacements= new Dictionary<string, string>()
|
private static readonly Dictionary<string, string> hintToCanonicalReplacement= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||||
{
|
{
|
||||||
{W3cHints.EMAIL, View.AutofillHintEmailAddress},
|
{W3cHints.EMAIL, View.AutofillHintEmailAddress},
|
||||||
{W3cHints.USERNAME, View.AutofillHintUsername},
|
{W3cHints.USERNAME, View.AutofillHintUsername},
|
||||||
@@ -41,9 +101,9 @@ namespace keepass2android.services.AutofillBase
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public static bool IsValidHint(string hint)
|
public static bool IsSupportedHint(string hint)
|
||||||
{
|
{
|
||||||
return validHints.Contains(hint);
|
return _allSupportedHints.Contains(hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -53,7 +113,7 @@ namespace keepass2android.services.AutofillBase
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
foreach (var hint in hints)
|
foreach (var hint in hints)
|
||||||
{
|
{
|
||||||
if (IsValidHint(hint))
|
if (IsSupportedHint(hint))
|
||||||
{
|
{
|
||||||
filteredHints[i++] = hint;
|
filteredHints[i++] = hint;
|
||||||
}
|
}
|
||||||
@@ -69,16 +129,18 @@ namespace keepass2android.services.AutofillBase
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static List<string> ConvertToStoredHints(string[] supportedHints)
|
/// <summary>
|
||||||
|
/// transforms hints by replacing some W3cHints by their Android counterparts and transforming everything to lowercase
|
||||||
|
/// </summary>
|
||||||
|
public static List<string> ConvertToCanonicalHints(string[] supportedHints)
|
||||||
{
|
{
|
||||||
List<string> result = new List<string>();
|
List<string> result = new List<string>();
|
||||||
foreach (string hint in supportedHints)
|
foreach (string hint in supportedHints)
|
||||||
{
|
{
|
||||||
string storedHint = hint;
|
string canonicalHint;
|
||||||
if (hintReplacements.ContainsKey(hint))
|
if (!hintToCanonicalReplacement.TryGetValue(hint, out canonicalHint))
|
||||||
storedHint = hintReplacements[hint];
|
canonicalHint = hint;
|
||||||
result.Add(storedHint);
|
result.Add(canonicalHint.ToLower());
|
||||||
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,89 @@
|
|||||||
using Android.App.Assist;
|
using System.Collections.Generic;
|
||||||
|
using Android.App.Assist;
|
||||||
using Android.Views.Autofill;
|
using Android.Views.Autofill;
|
||||||
|
|
||||||
namespace keepass2android.services.AutofillBase.model
|
namespace keepass2android.services.AutofillBase.model
|
||||||
{
|
{
|
||||||
public class FilledAutofillField
|
public class FilledAutofillField
|
||||||
{
|
{
|
||||||
public string TextValue { get; set; }
|
private string[] _autofillHints;
|
||||||
|
public string TextValue { get; set; }
|
||||||
public long? DateValue { get; set; }
|
public long? DateValue { get; set; }
|
||||||
public bool? ToggleValue { get; set; }
|
public bool? ToggleValue { get; set; }
|
||||||
|
|
||||||
public string[] AutofillHints { get; set; }
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
public FilledAutofillField()
|
/// returns the autofill hints for the filled field. These are always lowercased for simpler string comparison.
|
||||||
|
/// </summary>
|
||||||
|
public string[] AutofillHints
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _autofillHints;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_autofillHints = value;
|
||||||
|
for (int i = 0; i < _autofillHints.Length; i++)
|
||||||
|
_autofillHints[i] = _autofillHints[i].ToLower();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Protected { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public FilledAutofillField()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
public FilledAutofillField(AssistStructure.ViewNode viewNode)
|
||||||
|
{
|
||||||
|
|
||||||
|
string[] rawHints = AutofillHintsHelper.FilterForSupportedHints(viewNode.GetAutofillHints());
|
||||||
|
List<string> hintList = new List<string>();
|
||||||
|
|
||||||
|
string nextHint = null;
|
||||||
|
for (int i = 0; i < rawHints.Length; i++)
|
||||||
|
{
|
||||||
|
string hint = rawHints[i];
|
||||||
|
if (i < rawHints.Length - 1)
|
||||||
|
{
|
||||||
|
nextHint = rawHints[i + 1];
|
||||||
|
}
|
||||||
|
// First convert the compound W3C autofill hints
|
||||||
|
if (W3cHints.isW3cSectionPrefix(hint) && i < rawHints.Length - 1)
|
||||||
|
{
|
||||||
|
hint = rawHints[++i];
|
||||||
|
CommonUtil.logd($"Hint is a W3C section prefix; using {hint} instead");
|
||||||
|
if (i < rawHints.Length - 1)
|
||||||
|
{
|
||||||
|
nextHint = rawHints[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (W3cHints.isW3cTypePrefix(hint) && nextHint != null && W3cHints.isW3cTypeHint(nextHint))
|
||||||
|
{
|
||||||
|
hint = nextHint;
|
||||||
|
i++;
|
||||||
|
CommonUtil.logd($"Hint is a W3C type prefix; using {hint} instead");
|
||||||
|
}
|
||||||
|
if (W3cHints.isW3cAddressType(hint) && nextHint != null)
|
||||||
|
{
|
||||||
|
hint = nextHint;
|
||||||
|
i++;
|
||||||
|
CommonUtil.logd($"Hint is a W3C address prefix; using {hint} instead");
|
||||||
|
}
|
||||||
|
|
||||||
/*public FilledAutofillField(AssistStructure.ViewNode viewNode)
|
// Then check if the "actual" hint is supported.
|
||||||
{
|
if (AutofillHintsHelper.IsSupportedHint(hint))
|
||||||
AutofillHintsHelper = AutofillHelper.FilterForSupportedHints(viewNode.GetAutofillHints());
|
{
|
||||||
|
hintList.Add(hint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CommonUtil.loge($"Invalid hint: {rawHints[i]}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AutofillHints = hintList.ToArray();
|
||||||
|
|
||||||
//TODO port updated FilledAutofillField?
|
//TODO port updated FilledAutofillField
|
||||||
AutofillValue autofillValue = viewNode.AutofillValue;
|
AutofillValue autofillValue = viewNode.AutofillValue;
|
||||||
if (autofillValue != null)
|
if (autofillValue != null)
|
||||||
{
|
{
|
||||||
@@ -41,9 +105,9 @@ namespace keepass2android.services.AutofillBase.model
|
|||||||
TextValue = autofillValue.TextValue;
|
TextValue = autofillValue.TextValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
||||||
public bool IsNull()
|
public bool IsNull()
|
||||||
{
|
{
|
||||||
return TextValue == null && DateValue == null && ToggleValue == null;
|
return TextValue == null && DateValue == null && ToggleValue == null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Android.Service.Autofill;
|
using Android.Service.Autofill;
|
||||||
using Android.Util;
|
using Android.Util;
|
||||||
using Android.Views;
|
using Android.Views;
|
||||||
@@ -12,121 +13,48 @@ namespace keepass2android.services.AutofillBase.model
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class FilledAutofillFieldCollection
|
public class FilledAutofillFieldCollection
|
||||||
{
|
{
|
||||||
public Dictionary<string, FilledAutofillField> HintMap { get; set; }
|
public Dictionary<string, FilledAutofillField> HintMap { get; }
|
||||||
public string DatasetName { get; set; }
|
public string DatasetName { get; set; }
|
||||||
|
|
||||||
public FilledAutofillFieldCollection(Dictionary<string, FilledAutofillField> hintMap, string datasetName = "")
|
public FilledAutofillFieldCollection(Dictionary<string, FilledAutofillField> hintMap, string datasetName = "")
|
||||||
{
|
{
|
||||||
HintMap = hintMap;
|
//recreate hint map making sure we compare case insensitive
|
||||||
|
HintMap = BuildHintMap();
|
||||||
|
foreach (var p in hintMap)
|
||||||
|
HintMap.Add(p.Key, p.Value);
|
||||||
DatasetName = datasetName;
|
DatasetName = datasetName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FilledAutofillFieldCollection() : this(new Dictionary<string, FilledAutofillField>())
|
public FilledAutofillFieldCollection() : this(BuildHintMap())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/// <summary>
|
private static Dictionary<string, FilledAutofillField> BuildHintMap()
|
||||||
|
{
|
||||||
|
return new Dictionary<string, FilledAutofillField>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
/// Adds a filledAutofillField to the collection, indexed by all of its hints.
|
/// Adds a filledAutofillField to the collection, indexed by all of its hints.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The add.</returns>
|
/// <returns>The add.</returns>
|
||||||
/// <param name="filledAutofillField">Filled autofill field.</param>
|
/// <param name="filledAutofillField">Filled autofill field.</param>
|
||||||
public void Add(FilledAutofillField filledAutofillField)
|
public void Add(FilledAutofillField filledAutofillField)
|
||||||
{
|
{
|
||||||
string[] autofillHints = filledAutofillField.AutofillHints;
|
foreach (string hint in filledAutofillField.AutofillHints)
|
||||||
|
{
|
||||||
string nextHint = null;
|
if (AutofillHintsHelper.IsSupportedHint(hint))
|
||||||
for (int i = 0; i < autofillHints.Length; i++)
|
|
||||||
{
|
|
||||||
string hint = autofillHints[i];
|
|
||||||
if (i < autofillHints.Length - 1)
|
|
||||||
{
|
|
||||||
nextHint = autofillHints[i + 1];
|
|
||||||
}
|
|
||||||
// First convert the compound W3C autofill hints
|
|
||||||
if (isW3cSectionPrefix(hint) && i < autofillHints.Length - 1)
|
|
||||||
{
|
|
||||||
hint = autofillHints[++i];
|
|
||||||
CommonUtil.logd($"Hint is a W3C section prefix; using {hint} instead");
|
|
||||||
if (i < autofillHints.Length - 1)
|
|
||||||
{
|
|
||||||
nextHint = autofillHints[i + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isW3cTypePrefix(hint) && nextHint != null && isW3cTypeHint(nextHint))
|
|
||||||
{
|
|
||||||
hint = nextHint;
|
|
||||||
i++;
|
|
||||||
CommonUtil.logd($"Hint is a W3C type prefix; using {hint} instead");
|
|
||||||
}
|
|
||||||
if (isW3cAddressType(hint) && nextHint != null)
|
|
||||||
{
|
|
||||||
hint = nextHint;
|
|
||||||
i++;
|
|
||||||
CommonUtil.logd($"Hint is a W3C address prefix; using {hint} instead");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then check if the "actual" hint is supported.
|
|
||||||
if (AutofillHintsHelper.IsValidHint(hint))
|
|
||||||
{
|
{
|
||||||
HintMap.Add(hint, filledAutofillField);
|
HintMap.Add(hint, filledAutofillField);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CommonUtil.loge($"Invalid hint: {autofillHints[i]}");
|
CommonUtil.loge($"Invalid hint: {hint}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static bool isW3cSectionPrefix(string hint)
|
|
||||||
{
|
|
||||||
return hint.StartsWith(W3cHints.PREFIX_SECTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool isW3cAddressType(string hint)
|
|
||||||
{
|
|
||||||
switch (hint)
|
|
||||||
{
|
|
||||||
case W3cHints.SHIPPING:
|
|
||||||
case W3cHints.BILLING:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool isW3cTypePrefix(string hint)
|
|
||||||
{
|
|
||||||
switch (hint)
|
|
||||||
{
|
|
||||||
case W3cHints.PREFIX_WORK:
|
|
||||||
case W3cHints.PREFIX_FAX:
|
|
||||||
case W3cHints.PREFIX_HOME:
|
|
||||||
case W3cHints.PREFIX_PAGER:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool isW3cTypeHint(string hint)
|
|
||||||
{
|
|
||||||
switch (hint)
|
|
||||||
{
|
|
||||||
case W3cHints.TEL:
|
|
||||||
case W3cHints.TEL_COUNTRY_CODE:
|
|
||||||
case W3cHints.TEL_NATIONAL:
|
|
||||||
case W3cHints.TEL_AREA_CODE:
|
|
||||||
case W3cHints.TEL_LOCAL:
|
|
||||||
case W3cHints.TEL_LOCAL_PREFIX:
|
|
||||||
case W3cHints.TEL_LOCAL_SUFFIX:
|
|
||||||
case W3cHints.TEL_EXTENSION:
|
|
||||||
case W3cHints.EMAIL:
|
|
||||||
case W3cHints.IMPP:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Log.Warn(CommonUtil.Tag, "Invalid W3C type hint: " + hint);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Populates a Dataset.Builder with appropriate values for each AutofillId
|
/// Populates a Dataset.Builder with appropriate values for each AutofillId
|
||||||
/// in a AutofillFieldMetadataCollection.
|
/// in a AutofillFieldMetadataCollection.
|
||||||
@@ -142,16 +70,10 @@ namespace keepass2android.services.AutofillBase.model
|
|||||||
public bool ApplyToFields(AutofillFieldMetadataCollection autofillFieldMetadataCollection, Dataset.Builder datasetBuilder)
|
public bool ApplyToFields(AutofillFieldMetadataCollection autofillFieldMetadataCollection, Dataset.Builder datasetBuilder)
|
||||||
{
|
{
|
||||||
bool setValueAtLeastOnce = false;
|
bool setValueAtLeastOnce = false;
|
||||||
List<string> allHints = autofillFieldMetadataCollection.AllAutofillHints;
|
|
||||||
for (int hintIndex = 0; hintIndex < allHints.Count; hintIndex++)
|
foreach (string hint in autofillFieldMetadataCollection.AllAutofillCanonicalHints)
|
||||||
{
|
{
|
||||||
string hint = allHints[hintIndex];
|
foreach (AutofillFieldMetadata autofillFieldMetadata in autofillFieldMetadataCollection.GetFieldsForHint(hint))
|
||||||
List<AutofillFieldMetadata> fillableAutofillFields = autofillFieldMetadataCollection.GetFieldsForHint(hint);
|
|
||||||
if (fillableAutofillFields == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
foreach (AutofillFieldMetadata autofillFieldMetadata in fillableAutofillFields)
|
|
||||||
{
|
{
|
||||||
FilledAutofillField filledAutofillField;
|
FilledAutofillField filledAutofillField;
|
||||||
if (!HintMap.TryGetValue(hint, out filledAutofillField) || (filledAutofillField == null))
|
if (!HintMap.TryGetValue(hint, out filledAutofillField) || (filledAutofillField == null))
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace keepass2android.services.AutofillBase.model
|
using Android.Util;
|
||||||
|
|
||||||
|
namespace keepass2android.services.AutofillBase.model
|
||||||
{
|
{
|
||||||
public class W3cHints
|
public class W3cHints
|
||||||
{
|
{
|
||||||
@@ -70,5 +72,56 @@
|
|||||||
private W3cHints()
|
private W3cHints()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static bool isW3cSectionPrefix(string hint)
|
||||||
|
{
|
||||||
|
return hint.ToLower().StartsWith(W3cHints.PREFIX_SECTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool isW3cAddressType(string hint)
|
||||||
|
{
|
||||||
|
switch (hint.ToLower())
|
||||||
|
{
|
||||||
|
case W3cHints.SHIPPING:
|
||||||
|
case W3cHints.BILLING:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool isW3cTypePrefix(string hint)
|
||||||
|
{
|
||||||
|
switch (hint.ToLower())
|
||||||
|
{
|
||||||
|
case W3cHints.PREFIX_WORK:
|
||||||
|
case W3cHints.PREFIX_FAX:
|
||||||
|
case W3cHints.PREFIX_HOME:
|
||||||
|
case W3cHints.PREFIX_PAGER:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool isW3cTypeHint(string hint)
|
||||||
|
{
|
||||||
|
switch (hint.ToLower())
|
||||||
|
{
|
||||||
|
case W3cHints.TEL:
|
||||||
|
case W3cHints.TEL_COUNTRY_CODE:
|
||||||
|
case W3cHints.TEL_NATIONAL:
|
||||||
|
case W3cHints.TEL_AREA_CODE:
|
||||||
|
case W3cHints.TEL_LOCAL:
|
||||||
|
case W3cHints.TEL_LOCAL_PREFIX:
|
||||||
|
case W3cHints.TEL_LOCAL_SUFFIX:
|
||||||
|
case W3cHints.TEL_EXTENSION:
|
||||||
|
case W3cHints.EMAIL:
|
||||||
|
case W3cHints.IMPP:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Log.Warn(CommonUtil.Tag, "Invalid W3C type hint: " + hint);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,32 +41,44 @@ namespace keepass2android.services.Kp2aAutofill
|
|||||||
if (!App.Kp2a.GetDb().Loaded || (App.Kp2a.QuickLocked))
|
if (!App.Kp2a.GetDb().Loaded || (App.Kp2a.QuickLocked))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
string username = App.Kp2a.GetDb().LastOpenedEntry.Entry.Strings.ReadSafe(PwDefs.UserNameField);
|
|
||||||
string password = App.Kp2a.GetDb().LastOpenedEntry.Entry.Strings.ReadSafe(PwDefs.PasswordField);
|
|
||||||
|
|
||||||
FilledAutofillField pwdField =
|
|
||||||
new FilledAutofillField
|
|
||||||
{
|
|
||||||
AutofillHints = new[] {View.AutofillHintPassword},
|
|
||||||
TextValue = password
|
|
||||||
};
|
|
||||||
|
|
||||||
FilledAutofillField userField = new FilledAutofillField
|
|
||||||
{
|
|
||||||
AutofillHints = new[] {View.AutofillHintUsername},
|
|
||||||
TextValue = username
|
|
||||||
};
|
|
||||||
|
|
||||||
FilledAutofillFieldCollection fieldCollection = new FilledAutofillFieldCollection();
|
FilledAutofillFieldCollection fieldCollection = new FilledAutofillFieldCollection();
|
||||||
fieldCollection.HintMap = new Dictionary<string, FilledAutofillField>();
|
|
||||||
fieldCollection.Add(userField);
|
|
||||||
fieldCollection.Add(pwdField);
|
|
||||||
|
|
||||||
fieldCollection.DatasetName = App.Kp2a.GetDb().LastOpenedEntry.Entry.Strings.ReadSafe(PwDefs.TitleField);
|
var pwEntry = App.Kp2a.GetDb().LastOpenedEntry.Entry;
|
||||||
|
foreach (string key in pwEntry.Strings.GetKeys())
|
||||||
|
{
|
||||||
|
FilledAutofillField field =
|
||||||
|
new FilledAutofillField
|
||||||
|
{
|
||||||
|
AutofillHints = new[] { GetCanonicalHintFromKp2aField(pwEntry, key) },
|
||||||
|
TextValue = pwEntry.Strings.ReadSafe(key),
|
||||||
|
Protected = pwEntry.Strings.Get(key).IsProtected
|
||||||
|
};
|
||||||
|
fieldCollection.Add(field);
|
||||||
|
}
|
||||||
|
//TODO add support for Keepass templates
|
||||||
|
//TODO add values like expiration?
|
||||||
|
//TODO if cc-exp is there, also set cc-exp-month etc.
|
||||||
|
|
||||||
|
fieldCollection.DatasetName = pwEntry.Strings.ReadSafe(PwDefs.TitleField);
|
||||||
|
|
||||||
return fieldCollection;
|
return fieldCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, string> keyToHint = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{PwDefs.UserNameField, View.AutofillHintUsername },
|
||||||
|
{PwDefs.PasswordField, View.AutofillHintPassword },
|
||||||
|
{PwDefs.UrlField, W3cHints.URL },
|
||||||
|
};
|
||||||
|
|
||||||
|
private string GetCanonicalHintFromKp2aField(PwEntry pwEntry, string key)
|
||||||
|
{
|
||||||
|
if (!keyToHint.TryGetValue(key, out string result))
|
||||||
|
result = key;
|
||||||
|
result = result.ToLower();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public override IAutofillIntentBuilder IntentBuilder => new Kp2aAutofillIntentBuilder();
|
public override IAutofillIntentBuilder IntentBuilder => new Kp2aAutofillIntentBuilder();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user