From afd309d9a8015dc93975b4e314d2bb811c0d3cac Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Mon, 17 Dec 2018 10:03:02 +0100 Subject: [PATCH] work on reducing popups for autofill/allow to disable autofill for query. not yet fully functional. refers to #455. --- src/PluginSdkBinding/PluginSdkBinding.csproj | 4 +- .../DisableAutofillForQueryActivity.cs | 110 ++++++++++++++++++ .../Resources/values/strings.xml | 2 + src/keepass2android/keepass2android.csproj | 1 + .../AutofillBase/AutofillServiceBase.cs | 50 +++++++- .../services/Kp2aAutofillIntentBuilder.cs | 10 ++ 6 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 src/keepass2android/DisableAutofillForQueryActivity.cs diff --git a/src/PluginSdkBinding/PluginSdkBinding.csproj b/src/PluginSdkBinding/PluginSdkBinding.csproj index 229ff6b3..5aa9740a 100644 --- a/src/PluginSdkBinding/PluginSdkBinding.csproj +++ b/src/PluginSdkBinding/PluginSdkBinding.csproj @@ -53,9 +53,11 @@ + + Jars\Keepass2AndroidPluginSDK2-release.aar + - diff --git a/src/keepass2android/DisableAutofillForQueryActivity.cs b/src/keepass2android/DisableAutofillForQueryActivity.cs new file mode 100644 index 00000000..e6153396 --- /dev/null +++ b/src/keepass2android/DisableAutofillForQueryActivity.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Android.App; +using Android.App.Assist; +using Android.Content; +using Android.OS; +using Android.Preferences; +using Android.Runtime; +using Android.Service.Autofill; +using Android.Util; +using Android.Views; +using Android.Views.Autofill; +using Android.Widget; +using keepass2android.services; +using keepass2android.services.AutofillBase; + +namespace keepass2android +{ + [Activity(Label = "DisableAutofillForQueryActivity")] + public class DisableAutofillForQueryActivity : Activity + { + public IAutofillIntentBuilder IntentBuilder = new Kp2aAutofillIntentBuilder(); + + public const string ExtraIsDisable = "EXTRA_IS_DISABLE"; + + protected void RestartApp() + { + Intent intent = IntentBuilder.GetRestartAppIntent(this); + StartActivity(intent); + Finish(); + } + + protected override void OnCreate(Bundle savedInstanceState) + { + base.OnCreate(savedInstanceState); + + + string requestedUrl = Intent.GetStringExtra(ChooseForAutofillActivityBase.ExtraQueryString); + if (requestedUrl == null) + { + Toast.MakeText(this, "Cannot execute query for null.", ToastLength.Long).Show(); + RestartApp(); + return; + } + + var prefs = PreferenceManager.GetDefaultSharedPreferences(this); + + bool isDisable = Intent.GetBooleanExtra(ExtraIsDisable, true); + + var disabledValues = prefs.GetStringSet("AutoFillDisabledQueries", new HashSet() { }).ToHashSet(); + if (isDisable) + { + disabledValues.Add(requestedUrl); + } + else + { + disabledValues.Remove(requestedUrl); + } + + + prefs.Edit().PutStringSet("AutoFillDisabledQueries", disabledValues).Commit(); + + bool isManual = Intent.GetBooleanExtra(ChooseForAutofillActivityBase.ExtraIsManualRequest, false); + + Intent reply = new Intent(); + FillResponse.Builder builder = new FillResponse.Builder(); + AssistStructure structure = (AssistStructure)Intent.GetParcelableExtra(AutofillManager.ExtraAssistStructure); + StructureParser parser = new StructureParser(this, structure); + try + { + parser.ParseForFill(isManual); + + } + catch (Java.Lang.SecurityException e) + { + Log.Warn(CommonUtil.Tag, "Security exception handling request"); + SetResult(Result.Canceled); + return; + } + + AutofillFieldMetadataCollection autofillFields = parser.AutofillFields; + + + var autofillIds = autofillFields.GetAutofillIds(); + builder.SetIgnoredIds(autofillIds); + Bundle state = new Bundle(); + state.PutStringArray("AutoFillDisabledQueries", disabledValues.ToArray()); + + builder.SetClientState(state); + try + { + var response = builder.Build(); + reply.PutExtra(AutofillManager.ExtraAuthenticationResult, response); + } + catch (Exception e) + { + Kp2aLog.LogUnexpectedError(e); + throw; + } + + SetResult(Result.Ok, reply); + + + Finish(); + } + } +} \ No newline at end of file diff --git a/src/keepass2android/Resources/values/strings.xml b/src/keepass2android/Resources/values/strings.xml index 2ae85580..405f676a 100644 --- a/src/keepass2android/Resources/values/strings.xml +++ b/src/keepass2android/Resources/values/strings.xml @@ -1178,6 +1178,8 @@ Initial public release Sorry, it looks like your device does not support opening the settings from inside the app. Please go manually to the system settings for AutoFill to enable the service. Show Autofill help Fill with Keepass2Android + Disable AutoFill for %1$s + Enable AutoFill for %1$s Could not associate web domain %1$s with app %2$s Keepass2Android has detected fingerprint hardware. Do you want to enable fingerprint unlock for this database? diff --git a/src/keepass2android/keepass2android.csproj b/src/keepass2android/keepass2android.csproj index 092f53af..ca1f7b4c 100644 --- a/src/keepass2android/keepass2android.csproj +++ b/src/keepass2android/keepass2android.csproj @@ -178,6 +178,7 @@ + diff --git a/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs b/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs index 352bc50e..1fabd0d9 100644 --- a/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs +++ b/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs @@ -1,7 +1,9 @@ using System; +using System.Collections.Generic; using System.Linq; using Android.Content; using Android.OS; +using Android.Preferences; using Android.Runtime; using Android.Service.Autofill; using Android.Util; @@ -14,6 +16,7 @@ namespace keepass2android.services.AutofillBase public interface IAutofillIntentBuilder { IntentSender GetAuthIntentSenderForResponse(Context context, string query, bool isManualRequest, bool autoReturnFromQuery); + IntentSender GetDisableIntentSenderForResponse(Context context, string query, bool isManualRequest, bool isDisable); Intent GetRestartAppIntent(Context context); int AppIconResource { get; } @@ -66,7 +69,7 @@ namespace keepass2android.services.AutofillBase var autofillIds = autofillFields.GetAutofillIds(); - if (autofillIds.Length != 0 && CanAutofill(query)) + if (autofillIds.Length != 0 && CanAutofill(query, isManual)) { var responseBuilder = new FillResponse.Builder(); @@ -76,6 +79,7 @@ namespace keepass2android.services.AutofillBase responseBuilder.AddDataset(entryDataset); AddQueryDataset(query, isManual, autofillIds, responseBuilder, !hasEntryDataset); + AddDisableDataset(query, autofillIds, responseBuilder, isManual); responseBuilder.SetSaveInfo(new SaveInfo.Builder(parser.AutofillFields.SaveType, parser.AutofillFields.GetAutofillIds()).Build()); @@ -117,9 +121,49 @@ namespace keepass2android.services.AutofillBase responseBuilder.AddDataset(datasetBuilder.Build()); } - private bool CanAutofill(string query) + + private void AddDisableDataset(string query, AutofillId[] autofillIds, FillResponse.Builder responseBuilder, bool isManual) { - return !(query == "androidapp://android" || query == "androidapp://"+this.PackageName); + bool isQueryDisabled = IsQueryDisabled(query); + if (isQueryDisabled && !isManual) + return; + bool isForDisable = !isQueryDisabled; + var sender = IntentBuilder.GetDisableIntentSenderForResponse(this, query, isManual, isForDisable); + + RemoteViews presentation = AutofillHelper.NewRemoteViews(PackageName, + GetString(isForDisable ? Resource.String.autofill_disable : Resource.String.autofill_enable, new Java.Lang.Object[] { query}), Resource.Drawable.ic_menu_close_grey); + + var datasetBuilder = new Dataset.Builder(presentation); + datasetBuilder.SetAuthentication(sender); + + foreach (var autofillId in autofillIds) + { + datasetBuilder.SetValue(autofillId, AutofillValue.ForText("PLACEHOLDER")); + } + + responseBuilder.AddDataset(datasetBuilder.Build()); + } + + private bool CanAutofill(string query, bool isManual) + { + if (query == "androidapp://android" || query == "androidapp://" + this.PackageName) + return false; + if (!isManual) + { + var isQueryDisabled = IsQueryDisabled(query); + if (isQueryDisabled) + return false; + } + return true; + } + + private bool IsQueryDisabled(string query) + { + var prefs = PreferenceManager.GetDefaultSharedPreferences(this); + var disabledValues = prefs.GetStringSet("AutoFillDisabledQueries", new List()); + + bool isQueryDisabled = disabledValues.Contains(query); + return isQueryDisabled; } public override void OnSaveRequest(SaveRequest request, SaveCallback callback) diff --git a/src/keepass2android/services/Kp2aAutofillIntentBuilder.cs b/src/keepass2android/services/Kp2aAutofillIntentBuilder.cs index 78a41289..903f9d8e 100644 --- a/src/keepass2android/services/Kp2aAutofillIntentBuilder.cs +++ b/src/keepass2android/services/Kp2aAutofillIntentBuilder.cs @@ -24,6 +24,16 @@ namespace keepass2android.services return PendingIntent.GetActivity(context, 0, intent, PendingIntentFlags.CancelCurrent).IntentSender; } + public IntentSender GetDisableIntentSenderForResponse(Context context, string query, bool isManualRequest, bool isDisable) + { + Intent intent = new Intent(context, typeof(DisableAutofillForQueryActivity)); + intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryString, query); + intent.PutExtra(ChooseForAutofillActivityBase.ExtraIsManualRequest, isManualRequest); + intent.PutExtra(DisableAutofillForQueryActivity.ExtraIsDisable, isDisable); + + return PendingIntent.GetActivity(context, 0, intent, PendingIntentFlags.CancelCurrent).IntentSender; + } + public Intent GetRestartAppIntent(Context context) { var intent = new Intent(context, typeof(SelectCurrentDbActivity));