diff --git a/src/Kp2aBusinessLogic/database/Database.cs b/src/Kp2aBusinessLogic/database/Database.cs
index c795e082..c236a806 100644
--- a/src/Kp2aBusinessLogic/database/Database.cs
+++ b/src/Kp2aBusinessLogic/database/Database.cs
@@ -289,6 +289,7 @@ namespace keepass2android
CanWrite = true;
_reloadRequested = false;
OtpAuxFileIoc = null;
+ LastOpenedEntry = null;
}
public void MarkAllGroupsAsDirty() {
diff --git a/src/Kp2aBusinessLogic/database/PwEntryOutput.cs b/src/Kp2aBusinessLogic/database/PwEntryOutput.cs
index 8ab57d0b..26d0ea18 100644
--- a/src/Kp2aBusinessLogic/database/PwEntryOutput.cs
+++ b/src/Kp2aBusinessLogic/database/PwEntryOutput.cs
@@ -56,5 +56,10 @@ namespace keepass2android
{
get { return _entry; }
}
+
+ ///
+ /// if the entry was selected by searching for a URL, the query URL is returned here.
+ ///
+ public string SearchUrl { get; set; }
}
}
\ No newline at end of file
diff --git a/src/keepass2android/ShareUrlResults.cs b/src/keepass2android/ShareUrlResults.cs
index a5083b18..c1703a59 100644
--- a/src/keepass2android/ShareUrlResults.cs
+++ b/src/keepass2android/ShareUrlResults.cs
@@ -80,8 +80,9 @@ namespace keepass2android
_db = App.Kp2a.GetDb();
if (App.Kp2a.DatabaseIsUnlocked)
{
- String searchUrl = ((SearchUrlTask)AppTask).UrlToSearchFor;
- Query(searchUrl);
+ var searchUrlTask = ((SearchUrlTask)AppTask);
+ String searchUrl = searchUrlTask.UrlToSearchFor;
+ Query(searchUrl, searchUrlTask.AutoReturnFromQuery);
}
// else: LockCloseListActivity.OnResume will trigger a broadcast (LockDatabase) which will cause the activity to be finished.
@@ -93,7 +94,7 @@ namespace keepass2android
AppTask.ToBundle(outState);
}
- private void Query(String url)
+ private void Query(string url, bool autoReturnFromQuery)
{
try
{
@@ -125,7 +126,7 @@ namespace keepass2android
}
//if there is exactly one match: open the entry
- if (Group.Entries.Count() == 1)
+ if ((Group.Entries.Count() == 1) && autoReturnFromQuery)
{
LaunchActivityForEntry(Group.Entries.Single(),0);
return;
diff --git a/src/keepass2android/app/AppTask.cs b/src/keepass2android/app/AppTask.cs
index d868344c..d407b50e 100644
--- a/src/keepass2android/app/AppTask.cs
+++ b/src/keepass2android/app/AppTask.cs
@@ -361,6 +361,7 @@ namespace keepass2android
{
base.Setup(b);
UrlToSearchFor = b.GetString(UrlToSearchKey);
+ AutoReturnFromQuery = b.GetBoolean(AutoReturnFromQueryKey, true);
}
public override IEnumerable Extras
{
@@ -369,9 +370,15 @@ namespace keepass2android
foreach (IExtra e in base.Extras)
yield return e;
yield return new StringExtra { Key=UrlToSearchKey, Value = UrlToSearchFor };
- }
+ yield return new BoolExtra { Key = AutoReturnFromQueryKey, Value = AutoReturnFromQuery };
+ }
}
- public override void AfterUnlockDatabase(PasswordActivity act)
+
+ public const String AutoReturnFromQueryKey = "AutoReturnFromQuery";
+
+ public bool AutoReturnFromQuery { get; set; }
+
+ public override void AfterUnlockDatabase(PasswordActivity act)
{
if (String.IsNullOrEmpty(UrlToSearchFor))
{
@@ -403,6 +410,12 @@ namespace keepass2android
base.PopulatePasswordAccessServiceIntent(intent);
intent.PutExtra(UrlToSearchKey, UrlToSearchFor);
}
+
+ public override void CompleteOnCreateEntryActivity(EntryActivity activity)
+ {
+ App.Kp2a.GetDb().LastOpenedEntry.SearchUrl = UrlToSearchFor;
+ base.CompleteOnCreateEntryActivity(activity);
+ }
}
@@ -516,15 +529,18 @@ namespace keepass2android
public override void CompleteOnCreateEntryActivity(EntryActivity activity)
{
- //if the database is readonly (or no URL exists), don't offer to modify the URL
- if ((App.Kp2a.GetDb().CanWrite == false) || (String.IsNullOrEmpty(UrlToSearchFor)))
+ App.Kp2a.GetDb().LastOpenedEntry.SearchUrl = UrlToSearchFor;
+
+ //if the database is readonly (or no URL exists), don't offer to modify the URL
+ if ((App.Kp2a.GetDb().CanWrite == false) || (String.IsNullOrEmpty(UrlToSearchFor)))
{
base.CompleteOnCreateEntryActivity(activity);
return;
}
+
- AskAddUrlThenCompleteCreate(activity, UrlToSearchFor);
+ AskAddUrlThenCompleteCreate(activity, UrlToSearchFor);
}
diff --git a/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs b/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs
index f363c96f..94cf6b1b 100644
--- a/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs
+++ b/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs
@@ -1,4 +1,5 @@
using System;
+using System.Linq;
using Android.Content;
using Android.OS;
using Android.Runtime;
@@ -6,12 +7,13 @@ using Android.Service.Autofill;
using Android.Util;
using Android.Views.Autofill;
using Android.Widget;
+using keepass2android.services.AutofillBase.model;
namespace keepass2android.services.AutofillBase
{
public interface IAutofillIntentBuilder
{
- IntentSender GetAuthIntentSenderForResponse(Context context, string query, bool isManualRequest);
+ IntentSender GetAuthIntentSenderForResponse(Context context, string query, bool isManualRequest, bool autoReturnFromQuery);
Intent GetRestartAppIntent(Context context);
int AppIconResource { get; }
@@ -67,19 +69,13 @@ namespace keepass2android.services.AutofillBase
if (responseAuth && autofillIds.Length != 0 && CanAutofill(query))
{
var responseBuilder = new FillResponse.Builder();
-
- var sender = IntentBuilder.GetAuthIntentSenderForResponse(this, query, isManual);
- RemoteViews presentation = AutofillHelper.NewRemoteViews(PackageName, GetString(Resource.String.autofill_sign_in_prompt), AppNames.LauncherIcon);
- var datasetBuilder = new Dataset.Builder(presentation);
- datasetBuilder.SetAuthentication(sender);
- //need to add placeholders so we can directly fill after ChooseActivity
- foreach (var autofillId in autofillIds)
- {
- datasetBuilder.SetValue(autofillId, AutofillValue.ForText("PLACEHOLDER"));
- }
+ var entryDataset = AddEntryDataset(query, parser);
+ bool hasEntryDataset = entryDataset != null;
+ if (entryDataset != null)
+ responseBuilder.AddDataset(entryDataset);
- responseBuilder.AddDataset(datasetBuilder.Build());
+ AddQueryDataset(query, isManual, autofillIds, responseBuilder, !hasEntryDataset);
callback.OnSuccess(responseBuilder.Build());
}
@@ -91,6 +87,36 @@ namespace keepass2android.services.AutofillBase
}
}
+ private Dataset AddEntryDataset(string query, StructureParser parser)
+ {
+ var filledAutofillFieldCollection = GetSuggestedEntry(query);
+ if (filledAutofillFieldCollection == null)
+ return null;
+ int partitionIndex = AutofillHintsHelper.GetPartitionIndex(parser.AutofillFields.FocusedAutofillCanonicalHints.FirstOrDefault());
+ FilledAutofillFieldCollection partitionData = AutofillHintsHelper.FilterForPartition(filledAutofillFieldCollection, partitionIndex);
+
+ return AutofillHelper.NewDataset(this, parser.AutofillFields, partitionData, IntentBuilder);
+ }
+
+ protected abstract FilledAutofillFieldCollection GetSuggestedEntry(string query);
+
+ private void AddQueryDataset(string query, bool isManual, AutofillId[] autofillIds, FillResponse.Builder responseBuilder, bool autoReturnFromQuery)
+ {
+ var sender = IntentBuilder.GetAuthIntentSenderForResponse(this, query, isManual, autoReturnFromQuery);
+ RemoteViews presentation = AutofillHelper.NewRemoteViews(PackageName,
+ GetString(Resource.String.autofill_sign_in_prompt), AppNames.LauncherIcon);
+
+ var datasetBuilder = new Dataset.Builder(presentation);
+ datasetBuilder.SetAuthentication(sender);
+ //need to add placeholders so we can directly fill after ChooseActivity
+ foreach (var autofillId in autofillIds)
+ {
+ datasetBuilder.SetValue(autofillId, AutofillValue.ForText("PLACEHOLDER"));
+ }
+
+ responseBuilder.AddDataset(datasetBuilder.Build());
+ }
+
private bool CanAutofill(string query)
{
return !(query == "androidapp://android" || query == "androidapp://"+this.PackageName);
diff --git a/src/keepass2android/services/AutofillBase/ChooseForAutofillActivityBase.cs b/src/keepass2android/services/AutofillBase/ChooseForAutofillActivityBase.cs
index 18c2c733..f088cc26 100644
--- a/src/keepass2android/services/AutofillBase/ChooseForAutofillActivityBase.cs
+++ b/src/keepass2android/services/AutofillBase/ChooseForAutofillActivityBase.cs
@@ -23,6 +23,7 @@ namespace keepass2android.services.AutofillBase
public static string ExtraQueryString => "EXTRA_QUERY_STRING";
public static string ExtraIsManualRequest => "EXTRA_IS_MANUAL_REQUEST";
+ public static string ExtraAutoReturnFromQuery => "EXTRA_AUTO_RETURN_FROM_QUERY";
public int RequestCodeQuery => 6245;
@@ -46,11 +47,11 @@ namespace keepass2android.services.AutofillBase
return;
}
- var i = GetQueryIntent(requestedUrl);
+ var i = GetQueryIntent(requestedUrl, Intent.GetBooleanExtra(ExtraAutoReturnFromQuery, true));
StartActivityForResult(i, RequestCodeQuery);
}
- protected abstract Intent GetQueryIntent(string requestedUrl);
+ protected abstract Intent GetQueryIntent(string requestedUrl, bool autoReturnFromQuery);
protected void RestartApp()
{
@@ -59,7 +60,7 @@ namespace keepass2android.services.AutofillBase
Finish();
}
- /*
+
public override void Finish()
{
if (ReplyIntent != null)
@@ -71,7 +72,7 @@ namespace keepass2android.services.AutofillBase
SetResult(Result.Canceled);
}
base.Finish();
- }*/
+ }
void OnFailure()
{
@@ -87,8 +88,7 @@ namespace keepass2android.services.AutofillBase
parser.ParseForFill(isManual);
AutofillFieldMetadataCollection autofillFields = parser.AutofillFields;
int partitionIndex = AutofillHintsHelper.GetPartitionIndex(autofillFields.FocusedAutofillCanonicalHints.FirstOrDefault());
- FilledAutofillFieldCollection partitionData =
- AutofillHintsHelper.FilterForPartition(clientFormDataMap, partitionIndex);
+ FilledAutofillFieldCollection partitionData = AutofillHintsHelper.FilterForPartition(clientFormDataMap, partitionIndex);
ReplyIntent = new Intent();
SetDatasetIntent(AutofillHelper.NewDataset(this, autofillFields, partitionData, IntentBuilder));
}
@@ -121,6 +121,7 @@ namespace keepass2android.services.AutofillBase
public abstract IAutofillIntentBuilder IntentBuilder { get; }
+
protected void SetResponseIntent(FillResponse fillResponse)
{
ReplyIntent.PutExtra(AutofillManager.ExtraAuthenticationResult, fillResponse);
diff --git a/src/keepass2android/services/Kp2aAutofill/ChooseForAutofillActivity.cs b/src/keepass2android/services/Kp2aAutofill/ChooseForAutofillActivity.cs
index c51dad86..0dcd33f3 100644
--- a/src/keepass2android/services/Kp2aAutofill/ChooseForAutofillActivity.cs
+++ b/src/keepass2android/services/Kp2aAutofill/ChooseForAutofillActivity.cs
@@ -24,13 +24,13 @@ namespace keepass2android.services.Kp2aAutofill
Permission = "keepass2android." + AppNames.PackagePart + ".permission.Kp2aChooseAutofill")]
public class ChooseForAutofillActivity : ChooseForAutofillActivityBase
{
- protected override Intent GetQueryIntent(string requestedUrl)
+ protected override Intent GetQueryIntent(string requestedUrl, bool autoReturnFromQuery)
{
//launch FileSelectActivity (which is root of the stack (exception: we're even below!)) with the appropriate task.
//will return the results later
Intent i = new Intent(this, typeof(FileSelectActivity));
//don't show user notifications when an entry is opened.
- var task = new SearchUrlTask() { UrlToSearchFor = requestedUrl, ShowUserNotifications = false };
+ var task = new SearchUrlTask() { UrlToSearchFor = requestedUrl, ShowUserNotifications = false, AutoReturnFromQuery = autoReturnFromQuery };
task.ToIntent(i);
return i;
}
@@ -41,29 +41,37 @@ namespace keepass2android.services.Kp2aAutofill
{
if (!App.Kp2a.GetDb().Loaded || (App.Kp2a.QuickLocked))
return null;
+ var entryOutput = App.Kp2a.GetDb().LastOpenedEntry;
+ return GetFilledAutofillFieldCollectionFromEntry(entryOutput, this);
+ }
+
+ public static FilledAutofillFieldCollection GetFilledAutofillFieldCollectionFromEntry(PwEntryOutput pwEntryOutput, Context context)
+ {
+ if (pwEntryOutput == null)
+ return null;
FilledAutofillFieldCollection fieldCollection = new FilledAutofillFieldCollection();
+ var pwEntry = pwEntryOutput.Entry;
- var pwEntry = App.Kp2a.GetDb().LastOpenedEntry.Entry;
foreach (string key in pwEntry.Strings.GetKeys())
{
FilledAutofillField field =
new FilledAutofillField
{
- AutofillHints = new[] { GetCanonicalHintFromKp2aField(pwEntry, key) },
+ AutofillHints = new[] {GetCanonicalHintFromKp2aField(pwEntry, key)},
TextValue = pwEntry.Strings.ReadSafe(key),
Protected = pwEntry.Strings.Get(key).IsProtected
};
fieldCollection.Add(field);
}
- if (IsCreditCard(pwEntry) && pwEntry.Expires)
+ if (IsCreditCard(pwEntry, context) && pwEntry.Expires)
{
DateTime expTime = pwEntry.ExpiryTime;
FilledAutofillField field =
new FilledAutofillField
{
- AutofillHints = new[] { View.AutofillHintCreditCardExpirationDate },
- DateValue = (long)(1000*TimeUtil.SerializeUnix(expTime)),
+ AutofillHints = new[] {View.AutofillHintCreditCardExpirationDate},
+ DateValue = (long) (1000 * TimeUtil.SerializeUnix(expTime)),
Protected = false
};
fieldCollection.Add(field);
@@ -71,7 +79,7 @@ namespace keepass2android.services.Kp2aAutofill
field =
new FilledAutofillField
{
- AutofillHints = new[] { View.AutofillHintCreditCardExpirationDay },
+ AutofillHints = new[] {View.AutofillHintCreditCardExpirationDay},
TextValue = expTime.Day.ToString(),
Protected = false
};
@@ -80,7 +88,7 @@ namespace keepass2android.services.Kp2aAutofill
field =
new FilledAutofillField
{
- AutofillHints = new[] { View.AutofillHintCreditCardExpirationMonth },
+ AutofillHints = new[] {View.AutofillHintCreditCardExpirationMonth},
TextValue = expTime.Month.ToString(),
Protected = false
};
@@ -89,13 +97,12 @@ namespace keepass2android.services.Kp2aAutofill
field =
new FilledAutofillField
{
- AutofillHints = new[] { View.AutofillHintCreditCardExpirationYear },
+ AutofillHints = new[] {View.AutofillHintCreditCardExpirationYear},
TextValue = expTime.Year.ToString(),
Protected = false
};
fieldCollection.Add(field);
}
-
fieldCollection.DatasetName = pwEntry.Strings.ReadSafe(PwDefs.TitleField);
@@ -103,11 +110,11 @@ namespace keepass2android.services.Kp2aAutofill
return fieldCollection;
}
- private bool IsCreditCard(PwEntry pwEntry)
+ private static bool IsCreditCard(PwEntry pwEntry, Context context)
{
return pwEntry.Strings.Exists("cc-number")
|| pwEntry.Strings.Exists("cc-csc")
- || pwEntry.Strings.Exists(GetString(Resource.String.TemplateField_CreditCard_CVV));
+ || pwEntry.Strings.Exists(context.GetString(Resource.String.TemplateField_CreditCard_CVV));
}
private static readonly Dictionary keyToHint = BuildKeyToHint();
@@ -133,7 +140,7 @@ namespace keepass2android.services.Kp2aAutofill
return result;
}
- private string GetCanonicalHintFromKp2aField(PwEntry pwEntry, string key)
+ private static string GetCanonicalHintFromKp2aField(PwEntry pwEntry, string key)
{
if (!keyToHint.TryGetValue(key, out string result))
result = key;
diff --git a/src/keepass2android/services/Kp2aAutofill/Kp2aAutofillService.cs b/src/keepass2android/services/Kp2aAutofill/Kp2aAutofillService.cs
index 90220048..7dc24713 100644
--- a/src/keepass2android/services/Kp2aAutofill/Kp2aAutofillService.cs
+++ b/src/keepass2android/services/Kp2aAutofill/Kp2aAutofillService.cs
@@ -4,6 +4,8 @@ using Android.App;
using Android.Content;
using Android.Runtime;
using keepass2android.services.AutofillBase;
+using keepass2android.services.AutofillBase.model;
+using keepass2android.services.Kp2aAutofill;
using AutofillServiceBase = keepass2android.services.AutofillBase.AutofillServiceBase;
namespace keepass2android.services
@@ -24,6 +26,14 @@ namespace keepass2android.services
{
}
+ protected override FilledAutofillFieldCollection GetSuggestedEntry(string query)
+ {
+ if (App.Kp2a.GetDb()?.LastOpenedEntry?.SearchUrl == query)
+ return ChooseForAutofillActivity.GetFilledAutofillFieldCollectionFromEntry(
+ App.Kp2a.GetDb()?.LastOpenedEntry, this);
+ return null;
+ }
+
public override IAutofillIntentBuilder IntentBuilder => new Kp2aAutofillIntentBuilder();
}
}
\ No newline at end of file
diff --git a/src/keepass2android/services/Kp2aAutofillIntentBuilder.cs b/src/keepass2android/services/Kp2aAutofillIntentBuilder.cs
index 26578e22..12830a83 100644
--- a/src/keepass2android/services/Kp2aAutofillIntentBuilder.cs
+++ b/src/keepass2android/services/Kp2aAutofillIntentBuilder.cs
@@ -15,11 +15,12 @@ namespace keepass2android.services
class Kp2aAutofillIntentBuilder: IAutofillIntentBuilder
{
- public IntentSender GetAuthIntentSenderForResponse(Context context, string query, bool isManualRequest)
+ public IntentSender GetAuthIntentSenderForResponse(Context context, string query, bool isManualRequest, bool autoReturnFromQuery)
{
Intent intent = new Intent(context, typeof(ChooseForAutofillActivity));
intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryString, query);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraIsManualRequest, isManualRequest);
+ intent.PutExtra(ChooseForAutofillActivityBase.ExtraAutoReturnFromQuery, autoReturnFromQuery);
return PendingIntent.GetActivity(context, 0, intent, PendingIntentFlags.CancelCurrent).IntentSender;
}