diff --git a/src/Android/Android.csproj b/src/Android/Android.csproj
index 3858e3023..f8a4d826d 100644
--- a/src/Android/Android.csproj
+++ b/src/Android/Android.csproj
@@ -291,8 +291,7 @@
-
-
+
diff --git a/src/Android/Autofill/AutofillHelpers.cs b/src/Android/Autofill/AutofillHelpers.cs
index 32ae0ce4e..5e4c38613 100644
--- a/src/Android/Autofill/AutofillHelpers.cs
+++ b/src/Android/Autofill/AutofillHelpers.cs
@@ -13,9 +13,9 @@ namespace Bit.Android.Autofill
{
public static class AutofillHelpers
{
- public static async Task> GetFillItemsAsync(Parser parser, ICipherService service)
+ public static async Task> GetFillItemsAsync(Parser parser, ICipherService service)
{
- var items = new List();
+ var items = new List();
if(parser.FieldCollection.FillableForLogin)
{
@@ -26,7 +26,7 @@ namespace Bit.Android.Autofill
allCiphers.AddRange(ciphers.Item2.ToList());
foreach(var cipher in allCiphers)
{
- items.Add(new CipherFilledItem(cipher));
+ items.Add(new FilledItem(cipher));
}
}
}
@@ -35,14 +35,14 @@ namespace Bit.Android.Autofill
var ciphers = await service.GetAllAsync();
foreach(var cipher in ciphers.Where(c => c.Type == App.Enums.CipherType.Card))
{
- items.Add(new CipherFilledItem(cipher));
+ items.Add(new FilledItem(cipher));
}
}
return items;
}
- public static FillResponse BuildFillResponse(Context context, Parser parser, List items)
+ public static FillResponse BuildFillResponse(Context context, Parser parser, List items)
{
var responseBuilder = new FillResponse.Builder();
if(items != null && items.Count > 0)
@@ -62,7 +62,7 @@ namespace Bit.Android.Autofill
return responseBuilder.Build();
}
- public static Dataset BuildDataset(Context context, FieldCollection fields, IFilledItem filledItem)
+ public static Dataset BuildDataset(Context context, FieldCollection fields, FilledItem filledItem)
{
var datasetBuilder = new Dataset.Builder(
BuildListView(context.PackageName, filledItem.Name, filledItem.Subtitle, filledItem.Icon));
@@ -100,13 +100,19 @@ namespace Bit.Android.Autofill
public static void AddSaveInfo(FillResponse.Builder responseBuilder, FieldCollection fields)
{
var saveType = fields.SaveType;
- if(saveType == SaveDataType.Generic)
+ var requiredIds = fields.GetRequiredSaveFields();
+ if(saveType == SaveDataType.Generic || requiredIds.Length == 0)
{
return;
}
- var saveInfo = new SaveInfo.Builder(saveType, fields.AutofillIds.ToArray()).Build();
- responseBuilder.SetSaveInfo(saveInfo);
+ var saveBuilder = new SaveInfo.Builder(saveType, requiredIds);
+ var optionalIds = fields.GetOptionalSaveIds();
+ if(optionalIds.Length > 0)
+ {
+ saveBuilder.SetOptionalIds(optionalIds);
+ }
+ responseBuilder.SetSaveInfo(saveBuilder.Build());
}
}
}
\ No newline at end of file
diff --git a/src/Android/Autofill/AutofillService.cs b/src/Android/Autofill/AutofillService.cs
index 05cc7059d..9e7bfc651 100644
--- a/src/Android/Autofill/AutofillService.cs
+++ b/src/Android/Autofill/AutofillService.cs
@@ -34,8 +34,7 @@ namespace Bit.Android.Autofill
parser.Parse();
if(string.IsNullOrWhiteSpace(parser.Uri) || parser.Uri == "androidapp://com.x8bit.bitwarden" ||
- parser.Uri == "androidapp://android" ||
- (!parser.FieldCollection.FillableForLogin && !parser.FieldCollection.FillableForCard))
+ parser.Uri == "androidapp://android" || !parser.FieldCollection.Fillable)
{
return;
}
@@ -95,6 +94,13 @@ namespace Bit.Android.Autofill
intent.PutExtra("autofillFrameworkUsername", savedItem.Login.Username);
intent.PutExtra("autofillFrameworkPassword", savedItem.Login.Password);
break;
+ case CipherType.Card:
+ intent.PutExtra("autofillFrameworkCardName", savedItem.Card.Name);
+ intent.PutExtra("autofillFrameworkCardNumber", savedItem.Card.Number);
+ intent.PutExtra("autofillFrameworkCardExpMonth", savedItem.Card.ExpMonth);
+ intent.PutExtra("autofillFrameworkCardExpYear", savedItem.Card.ExpYear);
+ intent.PutExtra("autofillFrameworkCardCode", savedItem.Card.Code);
+ break;
default:
Toast.MakeText(this, "Unable to save this type of form.", ToastLength.Short).Show();
return;
diff --git a/src/Android/Autofill/CipherFilledItem.cs b/src/Android/Autofill/CipherFilledItem.cs
deleted file mode 100644
index b94d31d2d..000000000
--- a/src/Android/Autofill/CipherFilledItem.cs
+++ /dev/null
@@ -1,146 +0,0 @@
-using System;
-using Android.Service.Autofill;
-using Android.Views.Autofill;
-using System.Linq;
-using Bit.App.Models;
-using Bit.App.Enums;
-using Bit.App.Models.Page;
-using Android.Views;
-
-namespace Bit.Android.Autofill
-{
- public class CipherFilledItem : IFilledItem
- {
- private Lazy _password;
- private string _cardNumber;
- private Lazy _cardExpMonth;
- private Lazy _cardExpYear;
- private Lazy _cardCode;
-
- public CipherFilledItem(Cipher cipher)
- {
- Name = cipher.Name?.Decrypt() ?? "--";
- Type = cipher.Type;
-
- switch(Type)
- {
- case CipherType.Login:
- Subtitle = cipher.Login.Username?.Decrypt() ?? string.Empty;
- Icon = Resource.Drawable.login;
- _password = new Lazy(() => cipher.Login.Password?.Decrypt());
- break;
- case CipherType.Card:
- Subtitle = cipher.Card.Brand?.Decrypt();
- _cardNumber = cipher.Card.Number?.Decrypt();
- if(!string.IsNullOrWhiteSpace(_cardNumber) && _cardNumber.Length >= 4)
- {
- if(!string.IsNullOrWhiteSpace(_cardNumber))
- {
- Subtitle += ", ";
- }
- Subtitle += ("*" + _cardNumber.Substring(_cardNumber.Length - 4));
- }
- Icon = Resource.Drawable.card;
- _cardCode = new Lazy(() => cipher.Card.Code?.Decrypt());
- _cardExpMonth = new Lazy(() => cipher.Card.ExpMonth?.Decrypt());
- _cardExpYear = new Lazy(() => cipher.Card.ExpYear?.Decrypt());
- break;
- default:
- break;
- }
- }
-
- public CipherFilledItem(VaultListPageModel.Cipher cipher)
- {
- Name = cipher.Name ?? "--";
- Type = cipher.Type;
-
- switch(Type)
- {
- case CipherType.Login:
- Subtitle = cipher.LoginUsername ?? string.Empty;
- _password = cipher.LoginPassword;
- Icon = Resource.Drawable.login;
- break;
- default:
- break;
- }
- }
-
- public string Name { get; set; }
- public string Subtitle { get; set; } = string.Empty;
- public int Icon { get; set; } = Resource.Drawable.login;
- public CipherType Type { get; set; }
-
- public bool ApplyToFields(FieldCollection fieldCollection, Dataset.Builder datasetBuilder)
- {
- if(!fieldCollection?.Fields.Any() ?? true)
- {
- return false;
- }
-
- var setValues = false;
- if(Type == CipherType.Login)
- {
- if(fieldCollection.PasswordFields.Any() && !string.IsNullOrWhiteSpace(_password.Value))
- {
- foreach(var f in fieldCollection.PasswordFields)
- {
- setValues = true;
- datasetBuilder.SetValue(f.AutofillId, AutofillValue.ForText(_password.Value));
- }
- }
-
- if(fieldCollection.UsernameFields.Any() && !string.IsNullOrWhiteSpace(Subtitle))
- {
- foreach(var f in fieldCollection.UsernameFields)
- {
- setValues = true;
- datasetBuilder.SetValue(f.AutofillId, AutofillValue.ForText(Subtitle));
- }
- }
- }
- else if(Type == CipherType.Card)
- {
- if(fieldCollection.HintToFieldsMap.ContainsKey(View.AutofillHintCreditCardNumber) &&
- !string.IsNullOrWhiteSpace(_cardNumber))
- {
- foreach(var f in fieldCollection.HintToFieldsMap[View.AutofillHintCreditCardNumber])
- {
- setValues = true;
- datasetBuilder.SetValue(f.AutofillId, AutofillValue.ForText(_cardNumber));
- }
- }
- if(fieldCollection.HintToFieldsMap.ContainsKey(View.AutofillHintCreditCardSecurityCode) &&
- !string.IsNullOrWhiteSpace(_cardCode.Value))
- {
- foreach(var f in fieldCollection.HintToFieldsMap[View.AutofillHintCreditCardSecurityCode])
- {
- setValues = true;
- datasetBuilder.SetValue(f.AutofillId, AutofillValue.ForText(_cardCode.Value));
- }
- }
- if(fieldCollection.HintToFieldsMap.ContainsKey(View.AutofillHintCreditCardExpirationMonth) &&
- !string.IsNullOrWhiteSpace(_cardExpMonth.Value))
- {
- foreach(var f in fieldCollection.HintToFieldsMap[View.AutofillHintCreditCardExpirationMonth])
- {
- setValues = true;
- datasetBuilder.SetValue(f.AutofillId, AutofillValue.ForText(_cardExpMonth.Value));
- }
- }
- if(fieldCollection.HintToFieldsMap.ContainsKey(View.AutofillHintCreditCardExpirationYear) &&
- !string.IsNullOrWhiteSpace(_cardExpYear.Value))
- {
- foreach(var f in fieldCollection.HintToFieldsMap[View.AutofillHintCreditCardExpirationYear])
- {
- setValues = true;
- datasetBuilder.SetValue(f.AutofillId, AutofillValue.ForText(_cardExpYear.Value));
- }
- }
- }
-
- return setValues;
- }
- }
-}
\ No newline at end of file
diff --git a/src/Android/Autofill/Field.cs b/src/Android/Autofill/Field.cs
index 9353a5b17..7e53e04d0 100644
--- a/src/Android/Autofill/Field.cs
+++ b/src/Android/Autofill/Field.cs
@@ -33,6 +33,7 @@ namespace Bit.Android.Autofill
var autofillOptions = node.GetAutofillOptions();
if(autofillOptions != null && autofillOptions.Length > 0)
{
+ ListValue = node.AutofillValue.ListValue;
TextValue = autofillOptions[node.AutofillValue.ListValue];
}
}
@@ -44,6 +45,10 @@ namespace Bit.Android.Autofill
{
TextValue = node.AutofillValue.TextValue;
}
+ else if(node.AutofillValue.IsToggle)
+ {
+ ToggleValue = node.AutofillValue.ToggleValue;
+ }
}
}
@@ -69,24 +74,9 @@ namespace Bit.Android.Autofill
public List AutofillOptions { get; set; }
public string TextValue { get; set; }
public long? DateValue { get; set; }
+ public int? ListValue { get; set; }
public bool? ToggleValue { get; set; }
- public int GetAutofillOptionIndex(string value)
- {
- if(AutofillOptions != null)
- {
- for(var i = 0; i < AutofillOptions.Count; i++)
- {
- if(AutofillOptions[i].Equals(value))
- {
- return i;
- }
- }
- }
-
- return -1;
- }
-
private void UpdateSaveTypeFromHints()
{
SaveType = SaveDataType.Generic;
diff --git a/src/Android/Autofill/FieldCollection.cs b/src/Android/Autofill/FieldCollection.cs
index 6cdfc1fc6..6f02c713c 100644
--- a/src/Android/Autofill/FieldCollection.cs
+++ b/src/Android/Autofill/FieldCollection.cs
@@ -58,7 +58,12 @@ namespace Bit.Android.Autofill
}
else
{
- _passwordFields = Fields.Where(f => f.InputType.HasFlag(InputTypes.TextVariationPassword)).ToList();
+ _passwordFields = Fields
+ .Where(f =>
+ f.InputType.HasFlag(InputTypes.TextVariationPassword) ||
+ f.InputType.HasFlag(InputTypes.TextVariationVisiblePassword) ||
+ f.InputType.HasFlag(InputTypes.TextVariationWebPassword))
+ .ToList();
if(!_passwordFields.Any())
{
_passwordFields = Fields.Where(f => f.IdEntry?.ToLower().Contains("password") ?? false).ToList();
@@ -116,6 +121,8 @@ namespace Bit.Android.Autofill
new string[] { View.AutofillHintName, View.AutofillHintPhone, View.AutofillHintPostalAddress,
View.AutofillHintPostalCode });
+ public bool Fillable => FillableForLogin || FillableForCard || FillableForIdentity;
+
public void Add(Field field)
{
if(Ids.Contains(field.Id))
@@ -165,15 +172,12 @@ namespace Bit.Android.Autofill
Type = App.Enums.CipherType.Login,
Login = new SavedItem.LoginItem
{
- Password = passwordField.TextValue
+ Password = GetFieldValue(passwordField)
}
};
var usernameField = Fields.TakeWhile(f => f.Id != passwordField.Id).LastOrDefault();
- if(usernameField != null && !string.IsNullOrWhiteSpace(usernameField.TextValue))
- {
- savedItem.Login.Username = usernameField.TextValue;
- }
+ savedItem.Login.Username = GetFieldValue(usernameField);
return savedItem;
}
@@ -184,9 +188,11 @@ namespace Bit.Android.Autofill
Type = App.Enums.CipherType.Card,
Card = new SavedItem.CardItem
{
- Number = HintToFieldsMap.ContainsKey(View.AutofillHintCreditCardNumber) ?
- HintToFieldsMap[View.AutofillHintCreditCardNumber].FirstOrDefault(
- f => !string.IsNullOrWhiteSpace(f.TextValue))?.TextValue : null
+ Number = GetFieldValue(View.AutofillHintCreditCardNumber),
+ Name = GetFieldValue(View.AutofillHintName),
+ ExpMonth = GetFieldValue(View.AutofillHintCreditCardExpirationMonth, true),
+ ExpYear = GetFieldValue(View.AutofillHintCreditCardExpirationYear),
+ Code = GetFieldValue(View.AutofillHintCreditCardSecurityCode)
}
};
@@ -196,9 +202,105 @@ namespace Bit.Android.Autofill
return null;
}
+ public AutofillId[] GetOptionalSaveIds()
+ {
+ if(SaveType == SaveDataType.Password)
+ {
+ return UsernameFields.Select(f => f.AutofillId).ToArray();
+ }
+ else if(SaveType == SaveDataType.CreditCard)
+ {
+ var fieldList = new List();
+ if(HintToFieldsMap.ContainsKey(View.AutofillHintCreditCardSecurityCode))
+ {
+ fieldList.AddRange(HintToFieldsMap[View.AutofillHintCreditCardSecurityCode]);
+ }
+ if(HintToFieldsMap.ContainsKey(View.AutofillHintCreditCardExpirationYear))
+ {
+ fieldList.AddRange(HintToFieldsMap[View.AutofillHintCreditCardExpirationYear]);
+ }
+ if(HintToFieldsMap.ContainsKey(View.AutofillHintCreditCardExpirationMonth))
+ {
+ fieldList.AddRange(HintToFieldsMap[View.AutofillHintCreditCardExpirationMonth]);
+ }
+ if(HintToFieldsMap.ContainsKey(View.AutofillHintName))
+ {
+ fieldList.AddRange(HintToFieldsMap[View.AutofillHintName]);
+ }
+ return fieldList.Select(f => f.AutofillId).ToArray();
+ }
+
+ return new AutofillId[0];
+ }
+
+ public AutofillId[] GetRequiredSaveFields()
+ {
+ if(SaveType == SaveDataType.Password)
+ {
+ return PasswordFields.Select(f => f.AutofillId).ToArray();
+ }
+ else if(SaveType == SaveDataType.CreditCard && HintToFieldsMap.ContainsKey(View.AutofillHintCreditCardNumber))
+ {
+ return HintToFieldsMap[View.AutofillHintCreditCardNumber].Select(f => f.AutofillId).ToArray();
+ }
+
+ return new AutofillId[0];
+ }
+
private bool FocusedHintsContain(IEnumerable hints)
{
return hints.Any(h => FocusedHints.Contains(h));
}
+
+ private string GetFieldValue(string hint, bool monthValue = false)
+ {
+ if(HintToFieldsMap.ContainsKey(hint))
+ {
+ foreach(var field in HintToFieldsMap[hint])
+ {
+ var val = GetFieldValue(field, monthValue);
+ if(!string.IsNullOrWhiteSpace(val))
+ {
+ return val;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private string GetFieldValue(Field field, bool monthValue = false)
+ {
+ if(field == null)
+ {
+ return null;
+ }
+
+ if(!string.IsNullOrWhiteSpace(field.TextValue))
+ {
+ if(field.AutofillType == AutofillType.List && field.ListValue.HasValue && monthValue)
+ {
+ if(field.AutofillOptions.Count == 13)
+ {
+ return field.ListValue.ToString();
+ }
+ else if(field.AutofillOptions.Count == 12)
+ {
+ return (field.ListValue + 1).ToString();
+ }
+ }
+ return field.TextValue;
+ }
+ else if(field.DateValue.HasValue)
+ {
+ return field.DateValue.Value.ToString();
+ }
+ else if(field.ToggleValue.HasValue)
+ {
+ return field.ToggleValue.Value.ToString();
+ }
+
+ return null;
+ }
}
}
\ No newline at end of file
diff --git a/src/Android/Autofill/FilledItem.cs b/src/Android/Autofill/FilledItem.cs
new file mode 100644
index 000000000..878a0bf22
--- /dev/null
+++ b/src/Android/Autofill/FilledItem.cs
@@ -0,0 +1,291 @@
+using System;
+using Android.Service.Autofill;
+using Android.Views.Autofill;
+using System.Linq;
+using Bit.App.Models;
+using Bit.App.Enums;
+using Bit.App.Models.Page;
+using Android.Views;
+
+namespace Bit.Android.Autofill
+{
+ public class FilledItem
+ {
+ private Lazy _password;
+ private Lazy _cardName;
+ private string _cardNumber;
+ private Lazy _cardExpMonth;
+ private Lazy _cardExpYear;
+ private Lazy _cardCode;
+ private Lazy _idPhone;
+ private Lazy _idEmail;
+ private Lazy _idUsername;
+ private Lazy _idAddress;
+ private Lazy _idPostalCode;
+
+ public FilledItem(Cipher cipher)
+ {
+ Name = cipher.Name?.Decrypt(cipher.OrganizationId) ?? "--";
+ Type = cipher.Type;
+
+ switch(Type)
+ {
+ case CipherType.Login:
+ Subtitle = cipher.Login.Username?.Decrypt(cipher.OrganizationId) ?? string.Empty;
+ Icon = Resource.Drawable.login;
+ _password = new Lazy(() => cipher.Login.Password?.Decrypt(cipher.OrganizationId));
+ break;
+ case CipherType.Card:
+ Subtitle = cipher.Card.Brand?.Decrypt(cipher.OrganizationId);
+ _cardNumber = cipher.Card.Number?.Decrypt(cipher.OrganizationId);
+ if(!string.IsNullOrWhiteSpace(_cardNumber) && _cardNumber.Length >= 4)
+ {
+ if(!string.IsNullOrWhiteSpace(_cardNumber))
+ {
+ Subtitle += ", ";
+ }
+ Subtitle += ("*" + _cardNumber.Substring(_cardNumber.Length - 4));
+ }
+ Icon = Resource.Drawable.card;
+ _cardName = new Lazy(() => cipher.Card.CardholderName?.Decrypt(cipher.OrganizationId));
+ _cardCode = new Lazy(() => cipher.Card.Code?.Decrypt(cipher.OrganizationId));
+ _cardExpMonth = new Lazy(() => cipher.Card.ExpMonth?.Decrypt(cipher.OrganizationId));
+ _cardExpYear = new Lazy(() => cipher.Card.ExpYear?.Decrypt(cipher.OrganizationId));
+ break;
+ case CipherType.Identity:
+ var firstName = cipher.Identity?.FirstName?.Decrypt(cipher.OrganizationId) ?? " ";
+ var lastName = cipher.Identity?.LastName?.Decrypt(cipher.OrganizationId) ?? " ";
+ Subtitle = " ";
+ if(!string.IsNullOrWhiteSpace(firstName))
+ {
+ Subtitle = firstName;
+ }
+ if(!string.IsNullOrWhiteSpace(lastName))
+ {
+ if(!string.IsNullOrWhiteSpace(Subtitle))
+ {
+ Subtitle += " ";
+ }
+ Subtitle += lastName;
+ }
+ Icon = Resource.Drawable.id;
+ _idPhone = new Lazy(() => cipher.Identity.Phone?.Decrypt(cipher.OrganizationId));
+ _idEmail = new Lazy(() => cipher.Identity.Email?.Decrypt(cipher.OrganizationId));
+ _idUsername = new Lazy(() => cipher.Identity.Username?.Decrypt(cipher.OrganizationId));
+ _idAddress = new Lazy(() =>
+ {
+ var address = cipher.Identity.Address1?.Decrypt(cipher.OrganizationId);
+
+ var address2 = cipher.Identity.Address2?.Decrypt(cipher.OrganizationId);
+ if(!string.IsNullOrWhiteSpace(address2))
+ {
+ if(!string.IsNullOrWhiteSpace(address))
+ {
+ address += ", ";
+ }
+
+ address += address2;
+ }
+
+ var address3 = cipher.Identity.Address3?.Decrypt(cipher.OrganizationId);
+ if(!string.IsNullOrWhiteSpace(address3))
+ {
+ if(!string.IsNullOrWhiteSpace(address))
+ {
+ address += ", ";
+ }
+
+ address += address3;
+ }
+
+ return address;
+ });
+ _idPostalCode = new Lazy(() => cipher.Identity.PostalCode?.Decrypt(cipher.OrganizationId));
+ break;
+ default:
+ break;
+ }
+ }
+
+ public FilledItem(VaultListPageModel.Cipher cipher)
+ {
+ Name = cipher.Name ?? "--";
+ Type = cipher.Type;
+
+ switch(Type)
+ {
+ case CipherType.Login:
+ Subtitle = cipher.LoginUsername ?? string.Empty;
+ _password = cipher.LoginPassword;
+ Icon = Resource.Drawable.login;
+ break;
+ default:
+ break;
+ }
+ }
+
+ public string Name { get; set; }
+ public string Subtitle { get; set; } = string.Empty;
+ public int Icon { get; set; } = Resource.Drawable.login;
+ public CipherType Type { get; set; }
+
+ public bool ApplyToFields(FieldCollection fieldCollection, Dataset.Builder datasetBuilder)
+ {
+ if(!fieldCollection?.Fields.Any() ?? true)
+ {
+ return false;
+ }
+
+ var setValues = false;
+ if(Type == CipherType.Login)
+ {
+ if(fieldCollection.PasswordFields.Any() && !string.IsNullOrWhiteSpace(_password.Value))
+ {
+ foreach(var f in fieldCollection.PasswordFields)
+ {
+ var val = ApplyValue(f, _password.Value);
+ if(val != null)
+ {
+ setValues = true;
+ datasetBuilder.SetValue(f.AutofillId, val);
+ }
+ }
+ }
+
+ if(fieldCollection.UsernameFields.Any() && !string.IsNullOrWhiteSpace(Subtitle))
+ {
+ foreach(var f in fieldCollection.UsernameFields)
+ {
+ var val = ApplyValue(f, Subtitle);
+ if(val != null)
+ {
+ setValues = true;
+ datasetBuilder.SetValue(f.AutofillId, val);
+ }
+ }
+ }
+ }
+ else if(Type == CipherType.Card)
+ {
+ if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintCreditCardNumber,
+ new Lazy(() => _cardNumber)))
+ {
+ setValues = true;
+ }
+ if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintCreditCardSecurityCode, _cardCode))
+ {
+ setValues = true;
+ }
+ if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintCreditCardExpirationMonth, _cardExpMonth, true))
+ {
+ setValues = true;
+ }
+ if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintCreditCardExpirationYear, _cardExpYear))
+ {
+ setValues = true;
+ }
+ if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintName, _cardName))
+ {
+ setValues = true;
+ }
+ }
+ else if(Type == CipherType.Identity)
+ {
+ if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintPhone, _idPhone))
+ {
+ setValues = true;
+ }
+ if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintEmailAddress, _idEmail))
+ {
+ setValues = true;
+ }
+ if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintUsername, _idUsername))
+ {
+ setValues = true;
+ }
+ if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintPostalAddress, _idAddress))
+ {
+ setValues = true;
+ }
+ if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintPostalCode, _idPostalCode))
+ {
+ setValues = true;
+ }
+ if(ApplyValue(datasetBuilder, fieldCollection, View.AutofillHintName, new Lazy(() => Subtitle)))
+ {
+ setValues = true;
+ }
+ }
+
+ return setValues;
+ }
+
+ private static bool ApplyValue(Dataset.Builder builder, FieldCollection fieldCollection,
+ string hint, Lazy value, bool monthValue = false)
+ {
+ bool setValues = false;
+ if(fieldCollection.HintToFieldsMap.ContainsKey(hint) && !string.IsNullOrWhiteSpace(value.Value))
+ {
+ foreach(var f in fieldCollection.HintToFieldsMap[hint])
+ {
+ var val = ApplyValue(f, value.Value, monthValue);
+ if(val != null)
+ {
+ setValues = true;
+ builder.SetValue(f.AutofillId, val);
+ }
+ }
+ }
+ return setValues;
+ }
+
+ private static AutofillValue ApplyValue(Field field, string value, bool monthValue = false)
+ {
+ switch(field.AutofillType)
+ {
+ case AutofillType.Date:
+ if(long.TryParse(value, out long dateValue))
+ {
+ return AutofillValue.ForDate(dateValue);
+ }
+ break;
+ case AutofillType.List:
+ if(field.AutofillOptions != null)
+ {
+ if(monthValue && int.TryParse(value, out int monthIndex))
+ {
+ if(field.AutofillOptions.Count == 13)
+ {
+ return AutofillValue.ForList(monthIndex);
+ }
+ else if(field.AutofillOptions.Count >= monthIndex)
+ {
+ return AutofillValue.ForList(monthIndex - 1);
+ }
+ }
+
+ for(var i = 0; i < field.AutofillOptions.Count; i++)
+ {
+ if(field.AutofillOptions[i].Equals(value))
+ {
+ return AutofillValue.ForList(i);
+ }
+ }
+ }
+ break;
+ case AutofillType.Text:
+ return AutofillValue.ForText(value);
+ case AutofillType.Toggle:
+ if(bool.TryParse(value, out bool toggleValue))
+ {
+ return AutofillValue.ForToggle(toggleValue);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Android/Autofill/IFilledItem.cs b/src/Android/Autofill/IFilledItem.cs
deleted file mode 100644
index ca41ee9c9..000000000
--- a/src/Android/Autofill/IFilledItem.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using Android.Service.Autofill;
-using System;
-
-namespace Bit.Android.Autofill
-{
- public interface IFilledItem
- {
- string Name { get; set; }
- string Subtitle { get; set; }
- int Icon { get; set; }
- bool ApplyToFields(FieldCollection fieldCollection, Dataset.Builder datasetBuilder);
- }
-}
\ No newline at end of file
diff --git a/src/Android/MainActivity.cs b/src/Android/MainActivity.cs
index 92d7375e8..dbe79b55d 100644
--- a/src/Android/MainActivity.cs
+++ b/src/Android/MainActivity.cs
@@ -169,7 +169,7 @@ namespace Bit.Android
return;
}
- var items = new List { new CipherFilledItem(cipher) };
+ var items = new List { new FilledItem(cipher) };
var response = AutofillHelpers.BuildFillResponse(this, parser, items);
var replyIntent = new Intent();
replyIntent.PutExtra(AutofillManager.ExtraAuthenticationResult, response);
@@ -441,6 +441,11 @@ namespace Bit.Android
options.SaveName = Intent.GetStringExtra("autofillFrameworkName");
options.SaveUsername = Intent.GetStringExtra("autofillFrameworkUsername");
options.SavePassword = Intent.GetStringExtra("autofillFrameworkPassword");
+ options.SaveCardName = Intent.GetStringExtra("autofillFrameworkCardName");
+ options.SaveCardNumber = Intent.GetStringExtra("autofillFrameworkCardNumber");
+ options.SaveCardExpMonth = Intent.GetStringExtra("autofillFrameworkCardExpMonth");
+ options.SaveCardExpYear = Intent.GetStringExtra("autofillFrameworkCardExpYear");
+ options.SaveCardCode = Intent.GetStringExtra("autofillFrameworkCardCode");
}
return options;
diff --git a/src/App/Models/AppOptions.cs b/src/App/Models/AppOptions.cs
index 221bf4320..a2461773d 100644
--- a/src/App/Models/AppOptions.cs
+++ b/src/App/Models/AppOptions.cs
@@ -11,5 +11,10 @@ namespace Bit.App.Models
public string SaveName { get; set; }
public string SaveUsername { get; set; }
public string SavePassword { get; set; }
+ public string SaveCardName { get; set; }
+ public string SaveCardNumber { get; set; }
+ public string SaveCardExpMonth { get; set; }
+ public string SaveCardExpYear { get; set; }
+ public string SaveCardCode { get; set; }
}
}
diff --git a/src/App/Pages/Vault/VaultAddCipherPage.cs b/src/App/Pages/Vault/VaultAddCipherPage.cs
index 43d711f40..9826020d9 100644
--- a/src/App/Pages/Vault/VaultAddCipherPage.cs
+++ b/src/App/Pages/Vault/VaultAddCipherPage.cs
@@ -33,6 +33,11 @@ namespace Bit.App.Pages
private readonly string _defaultName;
private readonly string _defaultUsername;
private readonly string _defaultPassword;
+ private readonly string _defaultCardName;
+ private readonly string _defaultCardNumber;
+ private readonly int? _defaultCardExpMonth;
+ private readonly string _defaultCardExpYear;
+ private readonly string _defaultCardCode;
private readonly bool _fromAutofill;
private readonly bool _fromAutofillFramework;
private DateTime? _lastAction;
@@ -40,9 +45,17 @@ namespace Bit.App.Pages
public VaultAddCipherPage(AppOptions options)
: this(options.SaveType.Value, options.Uri, options.SaveName, options.FromAutofillFramework, false)
{
+ _fromAutofillFramework = options.FromAutofillFramework;
_defaultUsername = options.SaveUsername;
_defaultPassword = options.SavePassword;
- _fromAutofillFramework = options.FromAutofillFramework;
+ _defaultCardCode = options.SaveCardCode;
+ if(int.TryParse(options.SaveCardExpMonth, out int month) && month <= 12 && month >= 1)
+ {
+ _defaultCardExpMonth = month;
+ }
+ _defaultCardExpYear = options.SaveCardExpYear;
+ _defaultCardName = options.SaveCardName;
+ _defaultCardNumber = options.SaveCardNumber;
Init();
}
@@ -410,19 +423,39 @@ namespace Bit.App.Pages
{
CardCodeCell = new FormEntryCell(AppResources.SecurityCode, Keyboard.Numeric,
nextElement: NotesCell.Editor);
+ if(!string.IsNullOrWhiteSpace(_defaultCardCode))
+ {
+ CardCodeCell.Entry.Text = _defaultCardCode;
+ }
CardExpYearCell = new FormEntryCell(AppResources.ExpirationYear, Keyboard.Numeric,
nextElement: CardCodeCell.Entry);
+ if(!string.IsNullOrWhiteSpace(_defaultCardExpYear))
+ {
+ CardExpYearCell.Entry.Text = _defaultCardExpYear;
+ }
CardExpMonthCell = new FormPickerCell(AppResources.ExpirationMonth, new string[] {
"--", AppResources.January, AppResources.February, AppResources.March, AppResources.April,
AppResources.May, AppResources.June, AppResources.July, AppResources.August, AppResources.September,
AppResources.October, AppResources.November, AppResources.December
});
+ if(_defaultCardExpMonth.HasValue)
+ {
+ CardExpMonthCell.Picker.SelectedIndex = _defaultCardExpMonth.Value;
+ }
CardBrandCell = new FormPickerCell(AppResources.Brand, new string[] {
"--", "Visa", "Mastercard", "American Express", "Discover", "Diners Club",
"JCB", "Maestro", "UnionPay", AppResources.Other
});
CardNumberCell = new FormEntryCell(AppResources.Number, Keyboard.Numeric);
+ if(!string.IsNullOrWhiteSpace(_defaultCardNumber))
+ {
+ CardNumberCell.Entry.Text = _defaultCardNumber;
+ }
CardNameCell = new FormEntryCell(AppResources.CardholderName, nextElement: CardNumberCell.Entry);
+ if(!string.IsNullOrWhiteSpace(_defaultCardName))
+ {
+ CardNameCell.Entry.Text = _defaultCardName;
+ }
NameCell.NextElement = CardNameCell.Entry;
// Build sections