/// <summary> /// Wraps autofill data in a LoginCredential Dataset object which can then be sent back to the /// client View. /// </summary> /// <returns>The dataset.</returns> /// <param name="context">Context.</param> /// <param name="autofillFields">Autofill fields.</param> /// <param name="filledAutofillFieldCollection">Filled autofill field collection.</param> public static Dataset NewDataset(Context context, AutofillFieldMetadataCollection autofillFields, FilledAutofillFieldCollection filledAutofillFieldCollection, IAutofillIntentBuilder intentBuilder, Android.Widget.Inline.InlinePresentationSpec inlinePresentationSpec) { var datasetName = filledAutofillFieldCollection.DatasetName ?? "[noname]"; var datasetBuilder = new Dataset.Builder(NewRemoteViews(context.PackageName, datasetName, intentBuilder.AppIconResource)); datasetBuilder.SetId(datasetName); var setValueAtLeastOnce = filledAutofillFieldCollection.ApplyToFields(autofillFields, datasetBuilder); AddInlinePresentation(context, inlinePresentationSpec, datasetName, datasetBuilder, intentBuilder.AppIconResource); if (setValueAtLeastOnce) { return(datasetBuilder.Build()); } else { Kp2aLog.Log("Failed to set at least one value. #fields=" + autofillFields.GetAutofillIds().Length + " " + autofillFields.FocusedAutofillCanonicalHints); } return(null); }
/// <summary> /// Wraps autofill data in a LoginCredential Dataset object which can then be sent back to the /// client View. /// </summary> /// <returns>The dataset.</returns> /// <param name="context">Context.</param> /// <param name="autofillFields">Autofill fields.</param> /// <param name="filledAutofillFieldCollection">Filled autofill field collection.</param> public static Dataset NewDataset(Context context, AutofillFieldMetadataCollection autofillFields, FilledAutofillFieldCollection filledAutofillFieldCollection, IAutofillIntentBuilder intentBuilder) { var datasetName = filledAutofillFieldCollection.DatasetName; if (datasetName != null) { var datasetBuilder = new Dataset.Builder(NewRemoteViews(context.PackageName, datasetName, intentBuilder.AppIconResource)); datasetBuilder.SetId(datasetName); var setValueAtLeastOnce = filledAutofillFieldCollection.ApplyToFields(autofillFields, datasetBuilder); if (setValueAtLeastOnce) { return(datasetBuilder.Build()); } } return(null); }
/// <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) { Log.Debug(CommonUtil.Tag, "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); } if (AutofillFields.Empty) { var passwordFields = _editTextsWithoutHint .Where(IsPassword).ToList(); if (!passwordFields.Any()) { passwordFields = _editTextsWithoutHint.Where(HasPasswordHint).ToList(); } foreach (var passwordField in passwordFields) { AutofillFields.Add(new AutofillFieldMetadata(passwordField, new[] { View.AutofillHintPassword })); var usernameField = _editTextsWithoutHint.TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault(); if (usernameField != null) { AutofillFields.Add(new AutofillFieldMetadata(usernameField, new[] { View.AutofillHintUsername })); } } //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) { AutofillFields.Add(new AutofillFieldMetadata(_editTextsWithoutHint.First(), new[] { View.AutofillHintUsername })); } } //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) { AutofillFields.Add(new AutofillFieldMetadata(editText, new[] { IsPassword(editText) || HasPasswordHint(editText) ? View.AutofillHintPassword : View.AutofillHintUsername })); break; } } } 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; Log.Debug(CommonUtil.Tag, "no web domain. Using package name."); } return(webDomain); }