private List <Dataset> BuildEntryDatasets(string query, string queryDomain, string queryPackage, AutofillId[] autofillIds, StructureParser parser, DisplayWarning warning, IList <InlinePresentationSpec> inlinePresentationSpecs) { List <Dataset> result = new List <Dataset>(); Kp2aLog.Log("AF: BuildEntryDatasets"); var suggestedEntries = GetSuggestedEntries(query).ToDictionary(e => e.DatasetName, e => e); Kp2aLog.Log("AF: BuildEntryDatasets found " + suggestedEntries.Count + " entries"); int count = 0; foreach (var filledAutofillFieldCollection in suggestedEntries.Values) { if (filledAutofillFieldCollection == null) { continue; } var inlinePresentationSpec = AutofillHelper.ExtractSpec(inlinePresentationSpecs, count); if (warning == DisplayWarning.None) { FilledAutofillFieldCollection partitionData = AutofillHintsHelper.FilterForPartition(filledAutofillFieldCollection, parser.AutofillFields.FocusedAutofillCanonicalHints); Kp2aLog.Log("AF: Add dataset"); result.Add(AutofillHelper.NewDataset(this, parser.AutofillFields, partitionData, IntentBuilder, inlinePresentationSpec)); } else { //return an "auth" dataset (actually for just warning the user in case domain/package dont match) IntentSender sender = IntentBuilder.GetAuthIntentSenderForWarning(this, query, queryDomain, queryPackage, warning); var datasetName = filledAutofillFieldCollection.DatasetName; if (datasetName == null) { Kp2aLog.Log("AF: dataset name is null"); continue; } RemoteViews presentation = AutofillHelper.NewRemoteViews(PackageName, datasetName, AppNames.LauncherIcon); var datasetBuilder = new Dataset.Builder(presentation); datasetBuilder.SetAuthentication(sender); AutofillHelper.AddInlinePresentation(this, inlinePresentationSpec, datasetName, datasetBuilder, AppNames.LauncherIcon); //need to add placeholders so we can directly fill after ChooseActivity foreach (var autofillId in autofillIds) { datasetBuilder.SetValue(autofillId, AutofillValue.ForText("PLACEHOLDER")); } Kp2aLog.Log("AF: Add auth dataset"); result.Add(datasetBuilder.Build()); } count++; } return(result); }
public override void OnFillRequest(FillRequest request, CancellationSignal cancellationSignal, FillCallback callback) { bool isManual = (request.Flags & FillRequest.FlagManualRequest) != 0; CommonUtil.logd("onFillRequest " + (isManual ? "manual" : "auto")); var structure = request.FillContexts.Last().Structure; if (_lockTime + _lockTimeout < DateTime.Now) { _lockTime = DateTime.Now; //TODO support package signature verification as soon as this is supported in Keepass storage var clientState = request.ClientState; CommonUtil.logd("onFillRequest(): data=" + CommonUtil.BundleToString(clientState)); cancellationSignal.CancelEvent += (sender, e) => { Kp2aLog.Log("Cancel autofill not implemented yet."); _lockTime = DateTime.MinValue; }; // Parse AutoFill data in Activity StructureParser.AutofillTargetId query = null; var parser = new StructureParser(this, structure); try { query = parser.ParseForFill(isManual); } catch (Java.Lang.SecurityException e) { Log.Warn(CommonUtil.Tag, "Security exception handling request"); callback.OnFailure(e.Message); return; } AutofillFieldMetadataCollection autofillFields = parser.AutofillFields; InlineSuggestionsRequest inlineSuggestionsRequest = null; IList <InlinePresentationSpec> inlinePresentationSpecs = null; if (((int)Build.VERSION.SdkInt >= 30) && (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(GetString(Resource.String.InlineSuggestions_key), true))) { inlineSuggestionsRequest = request.InlineSuggestionsRequest; inlinePresentationSpecs = inlineSuggestionsRequest?.InlinePresentationSpecs; } var autofillIds = autofillFields.GetAutofillIds(); if (autofillIds.Length != 0 && CanAutofill(query, isManual)) { var responseBuilder = new FillResponse.Builder(); bool hasEntryDataset = false; IList <Dataset> entryDatasets = new List <Dataset>(); if (query.IncompatiblePackageAndDomain == false) { Kp2aLog.Log("AF: (query.IncompatiblePackageAndDomain == false)"); //domain and package are compatible. Use Domain if available and package otherwise. Can fill without warning. entryDatasets = BuildEntryDatasets(query.DomainOrPackage, query.WebDomain, query.PackageName, autofillIds, parser, DisplayWarning.None, inlinePresentationSpecs ).Where(ds => ds != null).ToList(); if (entryDatasets.Count > inlineSuggestionsRequest?.MaxSuggestionCount - 2 /*disable dataset and query*/) { //we have too many elements. disable inline suggestions inlinePresentationSpecs = null; entryDatasets = BuildEntryDatasets(query.DomainOrPackage, query.WebDomain, query.PackageName, autofillIds, parser, DisplayWarning.None, null ).Where(ds => ds != null).ToList(); } foreach (var entryDataset in entryDatasets ) { Kp2aLog.Log("AF: Got EntryDataset " + (entryDataset == null)); responseBuilder.AddDataset(entryDataset); hasEntryDataset = true; } } { if (query.WebDomain != null) { AddQueryDataset(query.WebDomain, query.WebDomain, query.PackageName, isManual, autofillIds, responseBuilder, !hasEntryDataset, query.IncompatiblePackageAndDomain ? DisplayWarning.FillDomainInUntrustedApp : DisplayWarning.None, AutofillHelper.ExtractSpec(inlinePresentationSpecs, entryDatasets.Count)); } else { AddQueryDataset(query.PackageNameWithPseudoSchema, query.WebDomain, query.PackageName, isManual, autofillIds, responseBuilder, !hasEntryDataset, DisplayWarning.None, AutofillHelper.ExtractSpec(inlinePresentationSpecs, entryDatasets.Count)); } } if (!PreferenceManager.GetDefaultSharedPreferences(this) .GetBoolean(GetString(Resource.String.NoAutofillDisabling_key), false)) { AddDisableDataset(query.DomainOrPackage, autofillIds, responseBuilder, isManual, AutofillHelper.ExtractSpec(inlinePresentationSpecs, entryDatasets.Count)); } if (PreferenceManager.GetDefaultSharedPreferences(this) .GetBoolean(GetString(Resource.String.OfferSaveCredentials_key), true)) { if (!CompatBrowsers.Contains(parser.PackageId)) { responseBuilder.SetSaveInfo(new SaveInfo.Builder(parser.AutofillFields.SaveType, parser.AutofillFields.GetAutofillIds()).Build()); } } Kp2aLog.Log("return autofill success"); callback.OnSuccess(responseBuilder.Build()); } else { Kp2aLog.Log("cannot autofill"); callback.OnSuccess(null); } } else { Kp2aLog.Log("Ignoring onFillRequest as there is another request going on."); } }