diff --git a/src/Android/Android.csproj b/src/Android/Android.csproj
index cab965c6c..ecaa06b23 100644
--- a/src/Android/Android.csproj
+++ b/src/Android/Android.csproj
@@ -287,10 +287,12 @@
-
-
-
-
+
+
+
+
+
+
@@ -298,8 +300,8 @@
-
-
+
+
@@ -328,7 +330,7 @@
-
+
diff --git a/src/Android/Autofill/AutofillFieldMetadataCollection.cs b/src/Android/Autofill/AutofillFieldMetadataCollection.cs
deleted file mode 100644
index 449a3f0d3..000000000
--- a/src/Android/Autofill/AutofillFieldMetadataCollection.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using System.Collections.Generic;
-using Android.Service.Autofill;
-using Android.Views;
-using Android.Views.Autofill;
-
-namespace Bit.Android.Autofill
-{
- public class AutofillFieldMetadataCollection
- {
- private int _size = 0;
-
- public List Ids { get; private set; } = new List();
- public List AutofillIds { get; private set; } = new List();
- public SaveDataType SaveType { get; private set; } = SaveDataType.Generic;
- public List AutofillHints { get; private set; } = new List();
- public List FocusedAutofillHints { get; private set; } = new List();
- public List Feilds { get; private set; }
- public IDictionary IdToFieldMap { get; private set; } =
- new Dictionary();
- public IDictionary> AutofillHintsToFieldsMap { get; private set; } =
- new Dictionary>();
-
- public void Add(AutofillFieldMetadata data)
- {
- _size++;
- SaveType |= data.SaveType;
- Ids.Add(data.Id);
- AutofillIds.Add(data.AutofillId);
- IdToFieldMap.Add(data.Id, data);
-
- if((data.AutofillHints?.Count ?? 0) > 0)
- {
- AutofillHints.AddRange(data.AutofillHints);
- if(data.IsFocused)
- {
- FocusedAutofillHints.AddRange(data.AutofillHints);
- }
-
- foreach(var hint in data.AutofillHints)
- {
- if(!AutofillHintsToFieldsMap.ContainsKey(hint))
- {
- AutofillHintsToFieldsMap.Add(hint, new List());
- }
-
- AutofillHintsToFieldsMap[hint].Add(data);
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/Android/Autofill/AutofillFrameworkService.cs b/src/Android/Autofill/AutofillFrameworkService.cs
deleted file mode 100644
index 123b85fe4..000000000
--- a/src/Android/Autofill/AutofillFrameworkService.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using Android;
-using Android.App;
-using Android.OS;
-using Android.Runtime;
-using Android.Service.Autofill;
-using Android.Views;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Bit.Android.Autofill
-{
- [Service(Permission = Manifest.Permission.BindAutofillService, Label = "bitwarden")]
- [IntentFilter(new string[] { "android.service.autofill.AutofillService" })]
- [MetaData("android.autofill", Resource = "@xml/autofillservice")]
- [Register("com.x8bit.bitwarden.Autofill.AutofillFrameworkService")]
- public class AutofillFrameworkService : global::Android.Service.Autofill.AutofillService
- {
- public override void OnFillRequest(FillRequest request, CancellationSignal cancellationSignal, FillCallback callback)
- {
- var structure = request.FillContexts?.LastOrDefault()?.Structure;
- if(structure == null)
- {
- return;
- }
-
- var clientState = request.ClientState;
-
- var parser = new StructureParser(structure);
- parser.ParseForFill();
-
- // build response
- var responseBuilder = new FillResponse.Builder();
-
- var username1 = new FilledAutofillField { TextValue = "username1" };
- var password1 = new FilledAutofillField { TextValue = "pass1" };
- var login1 = new Dictionary
- {
- { View.AutofillHintUsername, username1 },
- { View.AutofillHintPassword, password1 }
- };
- var coll = new FilledAutofillFieldCollection("Login 1 Name", login1);
-
- var username2 = new FilledAutofillField { TextValue = "username2" };
- var password2 = new FilledAutofillField { TextValue = "pass2" };
- var login2 = new Dictionary
- {
- { View.AutofillHintUsername, username2 },
- { View.AutofillHintPassword, password2 }
- };
- var col2 = new FilledAutofillFieldCollection("Login 2 Name", login2);
-
- var clientFormDataMap = new Dictionary
- {
- { "login-1-guid", coll },
- { "login-2-guid", col2 }
- };
-
- var response = AutofillHelper.NewResponse(this, false, parser.AutofillFields, clientFormDataMap);
- // end build response
-
- callback.OnSuccess(response);
- }
-
- public override void OnSaveRequest(SaveRequest request, SaveCallback callback)
- {
- var structure = request.FillContexts?.LastOrDefault()?.Structure;
- if(structure == null)
- {
- return;
- }
-
- var clientState = request.ClientState;
-
- var parser = new StructureParser(structure);
- parser.ParseForSave();
- var filledAutofillFieldCollection = parser.GetClientFormData();
- //SaveFilledAutofillFieldCollection(filledAutofillFieldCollection);
- }
- }
-}
diff --git a/src/Android/Autofill/AutofillHelper.cs b/src/Android/Autofill/AutofillHelpers.cs
similarity index 56%
rename from src/Android/Autofill/AutofillHelper.cs
rename to src/Android/Autofill/AutofillHelpers.cs
index bfc5e7313..0b5c6b204 100644
--- a/src/Android/Autofill/AutofillHelper.cs
+++ b/src/Android/Autofill/AutofillHelpers.cs
@@ -4,37 +4,38 @@ using Android.Content;
using Android.Service.Autofill;
using Android.Views;
using Android.Widget;
+using System.Diagnostics;
+using System.Linq;
namespace Bit.Android.Autofill
{
- public static class AutofillHelper
+ public static class AutofillHelpers
{
/**
* Wraps autofill data in a LoginCredential Dataset object which can then be sent back to the
* client View.
*/
- public static Dataset NewDataset(Context context, AutofillFieldMetadataCollection autofillFields,
- FilledAutofillFieldCollection filledAutofillFieldCollection, bool datasetAuth)
+ public static Dataset NewDataset(Context context, FieldCollection fields, IFilledItem filledItem, bool auth)
{
- var datasetName = filledAutofillFieldCollection.DatasetName;
- if(datasetName != null)
+ var itemName = filledItem.Name;
+ if(itemName != null)
{
Dataset.Builder datasetBuilder;
- if(datasetAuth)
+ if(auth)
{
datasetBuilder = new Dataset.Builder(
- NewRemoteViews(context.PackageName, datasetName, "username", Resource.Drawable.fa_lock));
+ NewRemoteViews(context.PackageName, itemName, filledItem.Subtitle, Resource.Drawable.fa_lock));
//IntentSender sender = AuthActivity.getAuthIntentSenderForDataset(context, datasetName);
//datasetBuilder.SetAuthentication(sender);
}
else
{
datasetBuilder = new Dataset.Builder(
- NewRemoteViews(context.PackageName, datasetName, "username", Resource.Drawable.user));
+ NewRemoteViews(context.PackageName, itemName, filledItem.Subtitle, Resource.Drawable.user));
}
- var setValueAtLeastOnce = filledAutofillFieldCollection.ApplyToFields(autofillFields, datasetBuilder);
- if(setValueAtLeastOnce)
+ var setValue = filledItem.ApplyToFields(fields, datasetBuilder);
+ if(setValue)
{
return datasetBuilder.Build();
}
@@ -56,59 +57,43 @@ namespace Bit.Android.Autofill
* Wraps autofill data in a Response object (essentially a series of Datasets) which can then
* be sent back to the client View.
*/
- public static FillResponse NewResponse(Context context, bool datasetAuth,
- AutofillFieldMetadataCollection autofillFields,
- IDictionary clientFormDataMap)
+ public static FillResponse NewResponse(Context context, bool auth, FieldCollection fields,
+ IDictionary items)
{
var responseBuilder = new FillResponse.Builder();
- if(clientFormDataMap != null)
+ if(items != null)
{
- foreach(var datasetName in clientFormDataMap.Keys)
+ foreach(var datasetName in items.Keys)
{
- if(clientFormDataMap.ContainsKey(datasetName))
+ var dataset = NewDataset(context, fields, items[datasetName], auth);
+ if(dataset != null)
{
- var dataset = NewDataset(context, autofillFields, clientFormDataMap[datasetName], datasetAuth);
- if(dataset != null)
- {
- responseBuilder.AddDataset(dataset);
- }
+ responseBuilder.AddDataset(dataset);
}
}
}
- if(autofillFields.SaveType != SaveDataType.Generic)
+ if(true || fields.SaveType != SaveDataType.Generic)
{
- responseBuilder.SetSaveInfo(
- new SaveInfo.Builder(autofillFields.SaveType, autofillFields.AutofillIds.ToArray()).Build());
+ var info = new SaveInfo.Builder(fields.SaveType, fields.AutofillIds.ToArray()).Build();
+ responseBuilder.SetSaveInfo(info);
return responseBuilder.Build();
}
else
{
- //Log.d(TAG, "These fields are not meant to be saved by autofill.");
+ Debug.WriteLine("These fields are not meant to be saved by autofill.");
return null;
}
}
- public static string[] FilterForSupportedHints(string[] hints)
+ public static List FilterForSupportedHints(string[] hints)
{
- if((hints?.Length ?? 0) == 0)
+ if(hints == null)
{
- return new string[0];
+ return new List();
}
- var filteredHints = new string[hints.Length];
- var i = 0;
- foreach(var hint in hints)
- {
- if(IsValidHint(hint))
- {
- filteredHints[i++] = hint;
- }
- }
-
- var finalFilteredHints = new string[i];
- Array.Copy(filteredHints, 0, finalFilteredHints, 0, i);
- return finalFilteredHints;
+ return hints.Where(h => IsValidHint(h)).ToList();
}
public static bool IsValidHint(string hint)
diff --git a/src/Android/Autofill/AutofillService.cs b/src/Android/Autofill/AutofillService.cs
new file mode 100644
index 000000000..53787ec16
--- /dev/null
+++ b/src/Android/Autofill/AutofillService.cs
@@ -0,0 +1,83 @@
+using Android;
+using Android.App;
+using Android.OS;
+using Android.Runtime;
+using Android.Service.Autofill;
+using Android.Views;
+using Bit.App.Abstractions;
+using System.Collections.Generic;
+using System.Linq;
+using XLabs.Ioc;
+
+namespace Bit.Android.Autofill
+{
+ [Service(Permission = Manifest.Permission.BindAutofillService, Label = "bitwarden")]
+ [IntentFilter(new string[] { "android.service.autofill.AutofillService" })]
+ [MetaData("android.autofill", Resource = "@xml/autofillservice")]
+ [Register("com.x8bit.bitwarden.Autofill.AutofillService")]
+ public class AutofillService : global::Android.Service.Autofill.AutofillService
+ {
+ private ICipherService _cipherService;
+
+ public async override void OnFillRequest(FillRequest request, CancellationSignal cancellationSignal, FillCallback callback)
+ {
+ var structure = request.FillContexts?.LastOrDefault()?.Structure;
+ if(structure == null)
+ {
+ return;
+ }
+
+ var clientState = request.ClientState;
+
+ var parser = new Parser(structure);
+ parser.ParseForFill();
+
+ if(!parser.FieldCollection.Fields.Any() || string.IsNullOrWhiteSpace(parser.Uri))
+ {
+ return;
+ }
+
+ if(_cipherService == null)
+ {
+ _cipherService = Resolver.Resolve();
+ }
+
+ // build response
+ var items = new Dictionary();
+ var ciphers = await _cipherService.GetAllAsync(parser.Uri);
+ if(ciphers.Item1.Any() || ciphers.Item2.Any())
+ {
+ var allCiphers = ciphers.Item1.ToList();
+ allCiphers.AddRange(ciphers.Item2.ToList());
+ foreach(var cipher in allCiphers)
+ {
+ items.Add(cipher.Id, new CipherFilledItem(cipher));
+ }
+ }
+
+ if(!items.Any())
+ {
+ return;
+ }
+
+ var response = AutofillHelpers.NewResponse(this, false, parser.FieldCollection, items);
+ callback.OnSuccess(response);
+ }
+
+ public override void OnSaveRequest(SaveRequest request, SaveCallback callback)
+ {
+ var structure = request.FillContexts?.LastOrDefault()?.Structure;
+ if(structure == null)
+ {
+ return;
+ }
+
+ var clientState = request.ClientState;
+
+ var parser = new Parser(structure);
+ parser.ParseForSave();
+ var filledAutofillFieldCollection = parser.GetClientFormData();
+ //SaveFilledAutofillFieldCollection(filledAutofillFieldCollection);
+ }
+ }
+}
diff --git a/src/Android/Autofill/CipherFilledItem.cs b/src/Android/Autofill/CipherFilledItem.cs
new file mode 100644
index 000000000..2af844f38
--- /dev/null
+++ b/src/Android/Autofill/CipherFilledItem.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using Android.Service.Autofill;
+using Android.Views;
+using Android.Views.Autofill;
+using System.Linq;
+using Android.Text;
+using Bit.App.Models;
+using Bit.App.Enums;
+
+namespace Bit.Android.Autofill
+{
+ public class CipherFilledItem : IFilledItem
+ {
+ private readonly Cipher _cipher;
+
+ public CipherFilledItem(Cipher cipher)
+ {
+ _cipher = cipher;
+ Name = cipher.Name?.Decrypt() ?? "--";
+
+ switch(cipher.Type)
+ {
+ case CipherType.Login:
+ Subtitle = _cipher.Login.Username?.Decrypt() ?? string.Empty;
+ break;
+ default:
+ break;
+ }
+ }
+
+ public string Name { get; set; }
+ public string Subtitle { get; set; } = string.Empty;
+
+ public bool ApplyToFields(FieldCollection fieldCollection, Dataset.Builder datasetBuilder)
+ {
+ if(_cipher.Type == CipherType.Login && _cipher.Login != null)
+ {
+ var passwordField = fieldCollection.Fields.FirstOrDefault(
+ f => f.InputType.HasFlag(InputTypes.TextVariationPassword));
+ if(passwordField == null)
+ {
+ return false;
+ }
+
+ var password = _cipher.Login.Password?.Decrypt();
+ if(string.IsNullOrWhiteSpace(password))
+ {
+ return false;
+ }
+
+ datasetBuilder.SetValue(passwordField.AutofillId, AutofillValue.ForText(password));
+
+ var usernameField = fieldCollection.Fields.TakeWhile(f => f.Id != passwordField.Id).LastOrDefault();
+ if(usernameField != null)
+ {
+ if(!string.IsNullOrWhiteSpace(Subtitle))
+ {
+ datasetBuilder.SetValue(usernameField.AutofillId, AutofillValue.ForText(Subtitle));
+ }
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Android/Autofill/AutofillFieldMetadata.cs b/src/Android/Autofill/Field.cs
similarity index 84%
rename from src/Android/Autofill/AutofillFieldMetadata.cs
rename to src/Android/Autofill/Field.cs
index 1eb9294a4..f8b8dd8e4 100644
--- a/src/Android/Autofill/AutofillFieldMetadata.cs
+++ b/src/Android/Autofill/Field.cs
@@ -8,29 +8,29 @@ using Android.Text;
namespace Bit.Android.Autofill
{
- public class AutofillFieldMetadata
+ public class Field
{
- private List _autofillHints;
+ private List _hints;
private string[] _autofillOptions;
- public AutofillFieldMetadata(ViewNode view)
+ public Field(ViewNode view)
{
_autofillOptions = view.GetAutofillOptions();
Id = view.Id;
AutofillId = view.AutofillId;
AutofillType = view.AutofillType;
InputType = view.InputType;
- IsFocused = view.IsFocused;
- AutofillHints = AutofillHelper.FilterForSupportedHints(view.GetAutofillHints())?.ToList() ?? new List();
+ Focused = view.IsFocused;
+ Hints = AutofillHelpers.FilterForSupportedHints(view.GetAutofillHints())?.ToList() ?? new List();
}
public SaveDataType SaveType { get; set; } = SaveDataType.Generic;
- public List AutofillHints
+ public List Hints
{
- get { return _autofillHints; }
+ get => _hints;
set
{
- _autofillHints = value;
+ _hints = value;
UpdateSaveTypeFromHints();
}
}
@@ -38,7 +38,7 @@ namespace Bit.Android.Autofill
public AutofillId AutofillId { get; private set; }
public AutofillType AutofillType { get; private set; }
public InputTypes InputType { get; private set; }
- public bool IsFocused { get; private set; }
+ public bool Focused { get; private set; }
/**
* When the {@link ViewNode} is a list that the user needs to choose a string from (i.e. a
@@ -60,12 +60,12 @@ namespace Bit.Android.Autofill
private void UpdateSaveTypeFromHints()
{
SaveType = SaveDataType.Generic;
- if(_autofillHints == null)
+ if(_hints == null)
{
return;
}
- foreach(var hint in _autofillHints)
+ foreach(var hint in _hints)
{
switch(hint)
{
diff --git a/src/Android/Autofill/FieldCollection.cs b/src/Android/Autofill/FieldCollection.cs
new file mode 100644
index 000000000..dd611143c
--- /dev/null
+++ b/src/Android/Autofill/FieldCollection.cs
@@ -0,0 +1,53 @@
+using System.Collections.Generic;
+using Android.Service.Autofill;
+using Android.Views.Autofill;
+
+namespace Bit.Android.Autofill
+{
+ public class FieldCollection
+ {
+ public HashSet Ids { get; private set; } = new HashSet();
+ public List AutofillIds { get; private set; } = new List();
+ public SaveDataType SaveType { get; private set; } = SaveDataType.Generic;
+ public List Hints { get; private set; } = new List();
+ public List FocusedHints { get; private set; } = new List();
+ public List Fields { get; private set; } = new List();
+ public IDictionary IdToFieldMap { get; private set; } =
+ new Dictionary();
+ public IDictionary> HintToFieldsMap { get; private set; } =
+ new Dictionary>();
+
+ public void Add(Field field)
+ {
+ if(Ids.Contains(field.Id))
+ {
+ return;
+ }
+
+ SaveType |= field.SaveType;
+ Ids.Add(field.Id);
+ Fields.Add(field);
+ AutofillIds.Add(field.AutofillId);
+ IdToFieldMap.Add(field.Id, field);
+
+ if((field.Hints?.Count ?? 0) > 0)
+ {
+ Hints.AddRange(field.Hints);
+ if(field.Focused)
+ {
+ FocusedHints.AddRange(field.Hints);
+ }
+
+ foreach(var hint in field.Hints)
+ {
+ if(!HintToFieldsMap.ContainsKey(hint))
+ {
+ HintToFieldsMap.Add(hint, new List());
+ }
+
+ HintToFieldsMap[hint].Add(field);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Android/Autofill/FilledAutofillField.cs b/src/Android/Autofill/FilledField.cs
similarity index 50%
rename from src/Android/Autofill/FilledAutofillField.cs
rename to src/Android/Autofill/FilledField.cs
index fe2ab14ad..3eae8e729 100644
--- a/src/Android/Autofill/FilledAutofillField.cs
+++ b/src/Android/Autofill/FilledField.cs
@@ -1,51 +1,51 @@
-using static Android.App.Assist.AssistStructure;
+using System.Collections.Generic;
+using static Android.App.Assist.AssistStructure;
namespace Bit.Android.Autofill
{
- public class FilledAutofillField
+ public class FilledField
{
- /**
- * Does not need to be serialized into persistent storage, so it's not exposed.
- */
- private string[] _autofillHints = null;
+ private IEnumerable _hints = null;
- public FilledAutofillField() { }
+ public FilledField() { }
- public FilledAutofillField(ViewNode viewNode)
+ public FilledField(ViewNode viewNode)
{
- _autofillHints = AutofillHelper.FilterForSupportedHints(viewNode.GetAutofillHints());
+ _hints = AutofillHelpers.FilterForSupportedHints(viewNode.GetAutofillHints());
var autofillValue = viewNode.AutofillValue;
- if(autofillValue != null)
+ if(autofillValue == null)
{
- if(autofillValue.IsList)
+ return;
+ }
+
+ if(autofillValue.IsList)
+ {
+ var autofillOptions = viewNode.GetAutofillOptions();
+ int index = autofillValue.ListValue;
+ if(autofillOptions != null && autofillOptions.Length > 0)
{
- var autofillOptions = viewNode.GetAutofillOptions();
- int index = autofillValue.ListValue;
- if(autofillOptions != null && autofillOptions.Length > 0)
- {
- TextValue = autofillOptions[index];
- }
- }
- else if(autofillValue.IsDate)
- {
- DateValue = autofillValue.DateValue;
- }
- else if(autofillValue.IsText)
- {
- // Using toString of AutofillValue.getTextValue in order to save it to
- // SharedPreferences.
- TextValue = autofillValue.TextValue;
+ TextValue = autofillOptions[index];
}
}
+ else if(autofillValue.IsDate)
+ {
+ DateValue = autofillValue.DateValue;
+ }
+ else if(autofillValue.IsText)
+ {
+ // Using toString of AutofillValue.getTextValue in order to save it to
+ // SharedPreferences.
+ TextValue = autofillValue.TextValue;
+ }
}
public string TextValue { get; set; }
public long? DateValue { get; set; }
public bool? ToggleValue { get; set; }
- public string[] GetAutofillHints()
+ public IEnumerable GetHints()
{
- return _autofillHints;
+ return _hints;
}
public bool IsNull()
@@ -56,16 +56,25 @@ namespace Bit.Android.Autofill
public override bool Equals(object o)
{
if(this == o)
+ {
return true;
+ }
if(o == null || GetType() != o.GetType())
+ {
return false;
+ }
- var that = (FilledAutofillField)o;
+ var that = o as FilledField;
if(TextValue != null ? !TextValue.Equals(that.TextValue) : that.TextValue != null)
+ {
return false;
+ }
+
if(DateValue != null ? !DateValue.Equals(that.DateValue) : that.DateValue != null)
+ {
return false;
+ }
return ToggleValue != null ? ToggleValue.Equals(that.ToggleValue) : that.ToggleValue == null;
}
diff --git a/src/Android/Autofill/FilledAutofillFieldCollection.cs b/src/Android/Autofill/FilledFieldCollection.cs
similarity index 62%
rename from src/Android/Autofill/FilledAutofillFieldCollection.cs
rename to src/Android/Autofill/FilledFieldCollection.cs
index 11c563c89..f103387f9 100644
--- a/src/Android/Autofill/FilledAutofillFieldCollection.cs
+++ b/src/Android/Autofill/FilledFieldCollection.cs
@@ -3,39 +3,42 @@ using System.Collections.Generic;
using Android.Service.Autofill;
using Android.Views;
using Android.Views.Autofill;
+using System.Linq;
+using Android.Text;
namespace Bit.Android.Autofill
{
- public class FilledAutofillFieldCollection
+ public class FilledFieldCollection : IFilledItem
{
- public FilledAutofillFieldCollection()
- : this(null, new Dictionary())
+ public FilledFieldCollection()
+ : this(null, new Dictionary())
+ { }
+
+ public FilledFieldCollection(string datasetName, IDictionary hintMap)
{
+ HintToFieldMap = hintMap;
+ Name = datasetName;
+ Subtitle = "username";
}
- public FilledAutofillFieldCollection(string datasetName, IDictionary hintMap)
- {
- HintMap = hintMap;
- DatasetName = datasetName;
- }
-
- public IDictionary HintMap { get; private set; }
- public string DatasetName { get; set; }
+ public IDictionary HintToFieldMap { get; private set; }
+ public string Name { get; set; }
+ public string Subtitle { get; set; }
/**
* Adds a {@code FilledAutofillField} to the collection, indexed by all of its hints.
*/
- public void Add(FilledAutofillField filledAutofillField)
+ public void Add(FilledField filledAutofillField)
{
if(filledAutofillField == null)
{
throw new ArgumentNullException(nameof(filledAutofillField));
}
- var autofillHints = filledAutofillField.GetAutofillHints();
+ var autofillHints = filledAutofillField.GetHints();
foreach(var hint in autofillHints)
{
- HintMap.Add(hint, filledAutofillField);
+ HintToFieldMap.Add(hint, filledAutofillField);
}
}
@@ -48,35 +51,33 @@ namespace Bit.Android.Autofill
* to Views specified in a {@code AutofillFieldMetadataCollection}, which represents the current
* page the user is on.
*/
- public bool ApplyToFields(AutofillFieldMetadataCollection autofillFieldMetadataCollection,
- Dataset.Builder datasetBuilder)
+ public bool ApplyToFields(FieldCollection fieldCollection, Dataset.Builder datasetBuilder)
{
var setValueAtLeastOnce = false;
- var allHints = autofillFieldMetadataCollection.AutofillHints;
+ var allHints = fieldCollection.Hints;
for(var hintIndex = 0; hintIndex < allHints.Count; hintIndex++)
{
var hint = allHints[hintIndex];
- if(!autofillFieldMetadataCollection.AutofillHintsToFieldsMap.ContainsKey(hint))
+ if(!fieldCollection.HintToFieldsMap.ContainsKey(hint))
{
continue;
}
- var fillableAutofillFields = autofillFieldMetadataCollection.AutofillHintsToFieldsMap[hint];
+ var fillableAutofillFields = fieldCollection.HintToFieldsMap[hint];
for(var autofillFieldIndex = 0; autofillFieldIndex < fillableAutofillFields.Count; autofillFieldIndex++)
{
- if(!HintMap.ContainsKey(hint))
+ if(!HintToFieldMap.ContainsKey(hint))
{
continue;
}
- var filledAutofillField = HintMap[hint];
- var autofillFieldMetadata = fillableAutofillFields[autofillFieldIndex];
- var autofillId = autofillFieldMetadata.AutofillId;
- var autofillType = autofillFieldMetadata.AutofillType;
- switch(autofillType)
+ var filledField = HintToFieldMap[hint];
+ var fieldMetadata = fillableAutofillFields[autofillFieldIndex];
+ var autofillId = fieldMetadata.AutofillId;
+ switch(fieldMetadata.AutofillType)
{
case AutofillType.List:
- int listValue = autofillFieldMetadata.GetAutofillOptionIndex(filledAutofillField.TextValue);
+ int listValue = fieldMetadata.GetAutofillOptionIndex(filledField.TextValue);
if(listValue != -1)
{
datasetBuilder.SetValue(autofillId, AutofillValue.ForList(listValue));
@@ -84,7 +85,7 @@ namespace Bit.Android.Autofill
}
break;
case AutofillType.Date:
- var dateValue = filledAutofillField.DateValue;
+ var dateValue = filledField.DateValue;
if(dateValue != null)
{
datasetBuilder.SetValue(autofillId, AutofillValue.ForDate(dateValue.Value));
@@ -92,7 +93,7 @@ namespace Bit.Android.Autofill
}
break;
case AutofillType.Text:
- var textValue = filledAutofillField.TextValue;
+ var textValue = filledField.TextValue;
if(textValue != null)
{
datasetBuilder.SetValue(autofillId, AutofillValue.ForText(textValue));
@@ -100,7 +101,7 @@ namespace Bit.Android.Autofill
}
break;
case AutofillType.Toggle:
- var toggleValue = filledAutofillField.ToggleValue;
+ var toggleValue = filledField.ToggleValue;
if(toggleValue != null)
{
datasetBuilder.SetValue(autofillId, AutofillValue.ForToggle(toggleValue.Value));
@@ -114,6 +115,16 @@ namespace Bit.Android.Autofill
}
}
+ if(!setValueAtLeastOnce)
+ {
+ var password = fieldCollection.Fields.FirstOrDefault(f => f.InputType == InputTypes.TextVariationPassword);
+ // datasetBuilder.SetValue(password.AutofillId, AutofillValue.ForText());
+ if(password != null)
+ {
+ var username = fieldCollection.Fields.TakeWhile(f => f.Id != password.Id).LastOrDefault();
+ }
+ }
+
return setValueAtLeastOnce;
}
@@ -124,15 +135,7 @@ namespace Bit.Android.Autofill
*/
public bool HelpsWithHints(List autofillHints)
{
- for(var i = 0; i < autofillHints.Count; i++)
- {
- if(HintMap.ContainsKey(autofillHints[i]) && !HintMap[autofillHints[i]].IsNull())
- {
- return true;
- }
- }
-
- return false;
+ return autofillHints.Any(h => HintToFieldMap.ContainsKey(h) && !HintToFieldMap[h].IsNull());
}
}
}
\ No newline at end of file
diff --git a/src/Android/Autofill/IFilledItem.cs b/src/Android/Autofill/IFilledItem.cs
new file mode 100644
index 000000000..5a81808af
--- /dev/null
+++ b/src/Android/Autofill/IFilledItem.cs
@@ -0,0 +1,12 @@
+using Android.Service.Autofill;
+using System;
+
+namespace Bit.Android.Autofill
+{
+ public interface IFilledItem
+ {
+ string Name { get; set; }
+ string Subtitle { get; set; }
+ bool ApplyToFields(FieldCollection fieldCollection, Dataset.Builder datasetBuilder);
+ }
+}
\ No newline at end of file
diff --git a/src/Android/Autofill/StructureParser.cs b/src/Android/Autofill/Parser.cs
similarity index 66%
rename from src/Android/Autofill/StructureParser.cs
rename to src/Android/Autofill/Parser.cs
index 20ea1ecf1..ec43d5e33 100644
--- a/src/Android/Autofill/StructureParser.cs
+++ b/src/Android/Autofill/Parser.cs
@@ -3,18 +3,26 @@ using Android.App.Assist;
namespace Bit.Android.Autofill
{
- public class StructureParser
+ public class Parser
{
private readonly AssistStructure _structure;
- private FilledAutofillFieldCollection _filledAutofillFieldCollection;
+ private string _uri;
+ private FilledFieldCollection _filledAutofillFieldCollection;
- public StructureParser(AssistStructure structure)
+ public Parser(AssistStructure structure)
{
_structure = structure;
}
- public AutofillFieldMetadataCollection AutofillFields { get; private set; }
- = new AutofillFieldMetadataCollection();
+ public FieldCollection FieldCollection { get; private set; } = new FieldCollection();
+ public string Uri
+ {
+ get => _uri;
+ set
+ {
+ _uri = $"androidapp://{value}";
+ }
+ }
public void ParseForFill()
{
@@ -31,7 +39,7 @@ namespace Bit.Android.Autofill
*/
private void Parse(bool forFill)
{
- _filledAutofillFieldCollection = new FilledAutofillFieldCollection();
+ _filledAutofillFieldCollection = new FilledFieldCollection();
for(var i = 0; i < _structure.WindowNodeCount; i++)
{
@@ -51,11 +59,17 @@ namespace Bit.Android.Autofill
{
if(forFill)
{
- AutofillFields.Add(new AutofillFieldMetadata(viewNode));
+ var f = new Field(viewNode);
+ FieldCollection.Add(f);
+
+ if(Uri == null)
+ {
+ Uri = viewNode.IdPackage;
+ }
}
else
{
- _filledAutofillFieldCollection.Add(new FilledAutofillField(viewNode));
+ _filledAutofillFieldCollection.Add(new FilledField(viewNode));
}
}
@@ -65,7 +79,7 @@ namespace Bit.Android.Autofill
}
}
- public FilledAutofillFieldCollection GetClientFormData()
+ public FilledFieldCollection GetClientFormData()
{
return _filledAutofillFieldCollection;
}