/// <summary> /// Traverse AssistStructure and add ViewNode metadata to a flat list. /// </summary> /// <returns>The parse.</returns> /// <param name="forFill">If set to <c>true</c> for fill.</param> /// <param name="isManualRequest"></param> string Parse(bool forFill, bool isManualRequest) { CommonUtil.logd("Parsing structure for " + Structure.ActivityComponent); var nodes = Structure.WindowNodeCount; ClientFormData = new FilledAutofillFieldCollection(); String webDomain = null; _editTextsWithoutHint.Clear(); for (int i = 0; i < nodes; i++) { var node = Structure.GetWindowNodeAt(i); var view = node.RootViewNode; ParseLocked(forFill, isManualRequest, view, ref webDomain); } List <AssistStructure.ViewNode> passwordFields = new List <AssistStructure.ViewNode>(); List <AssistStructure.ViewNode> usernameFields = new List <AssistStructure.ViewNode>(); if (AutofillFields.Empty) { passwordFields = _editTextsWithoutHint.Where(IsPassword).ToList(); if (!passwordFields.Any()) { passwordFields = _editTextsWithoutHint.Where(HasPasswordHint).ToList(); } foreach (var passwordField in passwordFields) { var usernameField = _editTextsWithoutHint.TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault(); if (usernameField != null) { usernameFields.Add(usernameField); } } //for some pages with two-step login, we don't see a password field and don't display the autofill for non-manual requests. But if the user forces autofill, //let's assume it is a username field: if (isManualRequest && !passwordFields.Any() && _editTextsWithoutHint.Count == 1) { usernameFields.Add(_editTextsWithoutHint.First()); } } //force focused fields to be included in autofill fields when request was triggered manually. This allows to fill fields which are "off" or don't have a hint (in case there are hints) if (isManualRequest) { foreach (AssistStructure.ViewNode editText in _editTextsWithoutHint) { if (editText.IsFocused) { if (IsPassword(editText) || HasPasswordHint(editText)) { passwordFields.Add(editText); } else { usernameFields.Add(editText); } break; } } } if (forFill) { foreach (var uf in usernameFields) { AutofillFields.Add(new AutofillFieldMetadata(uf, new[] { View.AutofillHintUsername })); } foreach (var pf in passwordFields) { AutofillFields.Add(new AutofillFieldMetadata(pf, new[] { View.AutofillHintPassword })); } } else { foreach (var uf in usernameFields) { ClientFormData.Add(new FilledAutofillField(uf, new[] { View.AutofillHintUsername })); } foreach (var pf in passwordFields) { ClientFormData.Add(new FilledAutofillField(pf, new[] { View.AutofillHintPassword })); } } String packageName = Structure.ActivityComponent.PackageName; if (!string.IsNullOrEmpty(webDomain)) { bool valid = Kp2aDigitalAssetLinksDataSource.Instance.IsValid(mContext, webDomain, packageName); if (!valid) { CommonUtil.loge($"DAL verification failed for {packageName}/{webDomain}"); webDomain = null; } } if (string.IsNullOrEmpty(webDomain)) { webDomain = "androidapp://" + packageName; CommonUtil.logd("no web domain. Using package name."); } return(webDomain); }
/// <summary> /// Traverse AssistStructure and add ViewNode metadata to a flat list. /// </summary> /// <returns>The parse.</returns> /// <param name="forFill">If set to <c>true</c> for fill.</param> /// <param name="isManualRequest"></param> AutofillTargetId Parse(bool forFill, bool isManualRequest) { AutofillTargetId result = new AutofillTargetId(); CommonUtil.logd("Parsing structure for " + Structure.ActivityComponent); var nodes = Structure.WindowNodeCount; ClientFormData = new FilledAutofillFieldCollection(); String webDomain = null; _editTextsWithoutHint.Clear(); for (int i = 0; i < nodes; i++) { var node = Structure.GetWindowNodeAt(i); var view = node.RootViewNode; ParseLocked(forFill, isManualRequest, view, ref webDomain); } List <AssistStructure.ViewNode> passwordFields = new List <AssistStructure.ViewNode>(); List <AssistStructure.ViewNode> usernameFields = new List <AssistStructure.ViewNode>(); if (AutofillFields.Empty) { passwordFields = _editTextsWithoutHint.Where(IsPassword).ToList(); if (!passwordFields.Any()) { passwordFields = _editTextsWithoutHint.Where(HasPasswordHint).ToList(); } usernameFields = _editTextsWithoutHint.Where(HasUsernameHint).ToList(); if (usernameFields.Any() == false) { foreach (var passwordField in passwordFields) { var usernameField = _editTextsWithoutHint .TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault(); if (usernameField != null) { usernameFields.Add(usernameField); } } } if (usernameFields.Any() == false) { //for some pages with two-step login, we don't see a password field and don't display the autofill for non-manual requests. But if the user forces autofill, //let's assume it is a username field: if (isManualRequest && !passwordFields.Any() && _editTextsWithoutHint.Count == 1) { usernameFields.Add(_editTextsWithoutHint.First()); } } } //force focused fields to be included in autofill fields when request was triggered manually. This allows to fill fields which are "off" or don't have a hint (in case there are hints) if (isManualRequest) { foreach (AssistStructure.ViewNode editText in _editTextsWithoutHint) { if (editText.IsFocused) { if (IsPassword(editText) || HasPasswordHint(editText)) { passwordFields.Add(editText); } else { usernameFields.Add(editText); } break; } } } if (forFill) { foreach (var uf in usernameFields) { AutofillFields.Add(new AutofillFieldMetadata(uf, new[] { View.AutofillHintUsername })); } foreach (var pf in passwordFields) { AutofillFields.Add(new AutofillFieldMetadata(pf, new[] { View.AutofillHintPassword })); } } else { foreach (var uf in usernameFields) { ClientFormData.Add(new FilledAutofillField(uf, new[] { View.AutofillHintUsername })); } foreach (var pf in passwordFields) { ClientFormData.Add(new FilledAutofillField(pf, new[] { View.AutofillHintPassword })); } } result.WebDomain = webDomain; result.PackageName = Structure.ActivityComponent.PackageName; if (!string.IsNullOrEmpty(webDomain) && !PreferenceManager.GetDefaultSharedPreferences(mContext).GetBoolean(mContext.GetString(Resource.String.NoDalVerification_key), false)) { result.IncompatiblePackageAndDomain = !kp2aDigitalAssetLinksDataSource.IsTrustedLink(webDomain, result.PackageName); if (result.IncompatiblePackageAndDomain) { CommonUtil.loge($"DAL verification failed for {result.PackageName}/{result.WebDomain}"); } } else { result.IncompatiblePackageAndDomain = false; } return(result); }