using System.Collections.Generic; using Android.Service.Autofill; using Android.Views.Autofill; using System.Linq; using Android.Text; namespace Bit.Android.Autofill { public class FieldCollection { private List _passwordFields = null; private List _usernameFields = null; 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 List PasswordFields { get { if(_passwordFields != null) { return _passwordFields; } _passwordFields = Fields.Where(f => f.InputType.HasFlag(InputTypes.TextVariationPassword)).ToList(); if(!_passwordFields.Any()) { _passwordFields = Fields.Where(f => f.IdEntry?.ToLower().Contains("password") ?? false).ToList(); } return _passwordFields; } } public List UsernameFields { get { if(_usernameFields != null) { return _usernameFields; } _usernameFields = new List(); foreach(var passwordField in PasswordFields) { var usernameField = Fields.TakeWhile(f => f.Id != passwordField.Id).LastOrDefault(); if(usernameField != null) { _usernameFields.Add(usernameField); } } return _usernameFields; } } public bool FillableForLogin => UsernameFields.Any(f => f.Focused) || PasswordFields.Any(f => f.Focused); public void Add(Field field) { if(Ids.Contains(field.Id)) { return; } _passwordFields = _usernameFields = null; Ids.Add(field.Id); Fields.Add(field); SaveType |= field.SaveType; 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); } } } public SavedItem GetSavedItem() { if(!Fields?.Any() ?? true) { return null; } var passwordField = PasswordFields.FirstOrDefault(f => !string.IsNullOrWhiteSpace(f.TextValue)); if(passwordField == null) { return null; } var savedItem = new SavedItem { Type = App.Enums.CipherType.Login, Login = new SavedItem.LoginItem { Password = passwordField.TextValue } }; var usernameField = Fields.TakeWhile(f => f.Id != passwordField.Id).LastOrDefault(); if(usernameField != null && !string.IsNullOrWhiteSpace(usernameField.TextValue)) { savedItem.Login.Username = usernameField.TextValue; } return savedItem; } } }