show entry notification when autofilling an entry with TOTP (to allow copying TOTP to clipboard)
fixes https://github.com/PhilippC/keepass2android/issues/1272
This commit is contained in:
		@@ -91,7 +91,29 @@ namespace keepass2android
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private static String ExtractHost(String url)
 | 
			
		||||
        public PwGroup SearchForUuid(Database database, string uuid)
 | 
			
		||||
        {
 | 
			
		||||
            SearchParameters sp = SearchParameters.None;
 | 
			
		||||
            sp.SearchInUuids = true;
 | 
			
		||||
            sp.SearchString = uuid;
 | 
			
		||||
 | 
			
		||||
            if (sp.RegularExpression) // Validate regular expression
 | 
			
		||||
            {
 | 
			
		||||
                new Regex(sp.SearchString);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            string strGroupName = _app.GetResourceString(UiStringKey.search_results);
 | 
			
		||||
            PwGroup pgResults = new PwGroup(true, true, strGroupName, PwIcon.EMailSearch) { IsVirtual = true };
 | 
			
		||||
 | 
			
		||||
            PwObjectList<PwEntry> listResults = pgResults.Entries;
 | 
			
		||||
 | 
			
		||||
            database.Root.SearchEntries(sp, listResults, new NullStatusLogger());
 | 
			
		||||
 | 
			
		||||
            return pgResults;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static String ExtractHost(String url)
 | 
			
		||||
		{
 | 
			
		||||
			return UrlUtil.GetHost(url.Trim());
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -174,10 +174,17 @@ namespace keepass2android
 | 
			
		||||
			PwGroup group = SearchHelper.SearchForExactUrl(this, url);
 | 
			
		||||
			
 | 
			
		||||
			return group;
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public PwGroup SearchForHost(String url, bool allowSubdomains) {
 | 
			
		||||
        }
 | 
			
		||||
        public PwGroup SearchForUuid(String uuid)
 | 
			
		||||
        {
 | 
			
		||||
            PwGroup group = SearchHelper.SearchForUuid(this, uuid);
 | 
			
		||||
 | 
			
		||||
            return group;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public PwGroup SearchForHost(String url, bool allowSubdomains) {
 | 
			
		||||
			PwGroup group = SearchHelper.SearchForHost(this, url, allowSubdomains);
 | 
			
		||||
			
 | 
			
		||||
			return group;
 | 
			
		||||
 
 | 
			
		||||
@@ -488,10 +488,11 @@ namespace keepass2android
 | 
			
		||||
			_pluginFieldReceiver = new PluginFieldReceiver(this);
 | 
			
		||||
			RegisterReceiver(_pluginFieldReceiver, new IntentFilter(Strings.ActionSetEntryField));
 | 
			
		||||
 | 
			
		||||
			new Thread(NotifyPluginsOnOpen).Start();
 | 
			
		||||
            var notifyPluginsOnOpenThread = new Thread(NotifyPluginsOnOpen);
 | 
			
		||||
            notifyPluginsOnOpenThread.Start();
 | 
			
		||||
 | 
			
		||||
			//the rest of the things to do depends on the current app task:
 | 
			
		||||
			AppTask.CompleteOnCreateEntryActivity(this);
 | 
			
		||||
			AppTask.CompleteOnCreateEntryActivity(this, notifyPluginsOnOpenThread);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        private void RemoveFromHistory()
 | 
			
		||||
 
 | 
			
		||||
@@ -63,6 +63,12 @@ namespace keepass2android
 | 
			
		||||
		    launchMode.Launch(act, i);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        public static void Launch(Activity act, OpenSpecificEntryTask task, ActivityLaunchMode launchMode)
 | 
			
		||||
        {
 | 
			
		||||
            Intent i = new Intent(act, typeof(ShareUrlResults));
 | 
			
		||||
            task.ToIntent(i);
 | 
			
		||||
            launchMode.Launch(act, i);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool IsSearchResult
 | 
			
		||||
        {
 | 
			
		||||
@@ -83,9 +89,8 @@ namespace keepass2android
 | 
			
		||||
 | 
			
		||||
            if (App.Kp2a.DatabaseIsUnlocked)
 | 
			
		||||
			{
 | 
			
		||||
			    var searchUrlTask = ((SearchUrlTask)AppTask);
 | 
			
		||||
			    String searchUrl = searchUrlTask.UrlToSearchFor;
 | 
			
		||||
				Query(searchUrl, searchUrlTask.AutoReturnFromQuery);	
 | 
			
		||||
			    
 | 
			
		||||
				Query();	
 | 
			
		||||
			}
 | 
			
		||||
            // else: LockCloseListActivity.OnResume will trigger a broadcast (LockDatabase) which will cause the activity to be finished.
 | 
			
		||||
 | 
			
		||||
@@ -99,12 +104,25 @@ namespace keepass2android
 | 
			
		||||
			AppTask.ToBundle(outState);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void Query(string url, bool autoReturnFromQuery)
 | 
			
		||||
		private void Query()
 | 
			
		||||
        {
 | 
			
		||||
            
 | 
			
		||||
            bool canAutoReturnFromQuery = true;
 | 
			
		||||
            bool shouldAutoReturnFromQuery = true;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                Group = GetSearchResultsForUrl(url);
 | 
			
		||||
				if (AppTask is SearchUrlTask searchUrlTask)
 | 
			
		||||
                {
 | 
			
		||||
                    String searchUrl = searchUrlTask.UrlToSearchFor;
 | 
			
		||||
                    canAutoReturnFromQuery = searchUrlTask.AutoReturnFromQuery;
 | 
			
		||||
                    shouldAutoReturnFromQuery = PreferenceManager.GetDefaultSharedPreferences(this)
 | 
			
		||||
                        .GetBoolean(GetString(Resource.String.AutoReturnFromQuery_key), true);
 | 
			
		||||
                    Group = GetSearchResultsForUrl(searchUrl);
 | 
			
		||||
                }
 | 
			
		||||
				else if (AppTask is OpenSpecificEntryTask openEntryTask)
 | 
			
		||||
                {
 | 
			
		||||
                    Group = GetSearchResultsForUuid(openEntryTask.EntryUuid);
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
            } catch (Exception e)
 | 
			
		||||
			{
 | 
			
		||||
				Toast.MakeText(this, e.Message, ToastLength.Long).Show();
 | 
			
		||||
@@ -114,7 +132,7 @@ namespace keepass2android
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			//if there is exactly one match: open the entry
 | 
			
		||||
			if ((Group.Entries.Count() == 1) && autoReturnFromQuery && PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(GetString(Resource.String.AutoReturnFromQuery_key),true))
 | 
			
		||||
			if ((Group.Entries.Count() == 1) && canAutoReturnFromQuery && shouldAutoReturnFromQuery)
 | 
			
		||||
			{
 | 
			
		||||
				LaunchActivityForEntry(Group.Entries.Single(),0);
 | 
			
		||||
				return;
 | 
			
		||||
@@ -131,32 +149,49 @@ namespace keepass2android
 | 
			
		||||
            FragmentManager.FindFragmentById<GroupListFragment>(Resource.Id.list_fragment).ListAdapter = new PwGroupListAdapter(this, Group);
 | 
			
		||||
 | 
			
		||||
			View selectOtherEntry = FindViewById (Resource.Id.select_other_entry);
 | 
			
		||||
            View createUrlEntry = FindViewById(Resource.Id.add_url_entry);
 | 
			
		||||
 | 
			
		||||
            var newTask = new SearchUrlTask() {AutoReturnFromQuery = false, UrlToSearchFor = url};
 | 
			
		||||
		    if (AppTask is SelectEntryTask currentSelectTask)
 | 
			
		||||
		        newTask.ShowUserNotifications = currentSelectTask.ShowUserNotifications;
 | 
			
		||||
            
 | 
			
		||||
            selectOtherEntry.Click += (sender, e) => {
 | 
			
		||||
				GroupActivity.Launch (this, newTask, new ActivityLaunchModeRequestCode(0));
 | 
			
		||||
            if (AppTask is OpenSpecificEntryTask)
 | 
			
		||||
            {
 | 
			
		||||
                selectOtherEntry.Visibility =  ViewStates.Gone;
 | 
			
		||||
                createUrlEntry.Visibility = ViewStates.Gone;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                var searchUrlTask = AppTask as SearchUrlTask;
 | 
			
		||||
                String searchUrl = searchUrlTask.UrlToSearchFor;
 | 
			
		||||
                selectOtherEntry.Visibility =  ViewStates.Visible;
 | 
			
		||||
 | 
			
		||||
                var newTask = new SearchUrlTask() { AutoReturnFromQuery = false, UrlToSearchFor = searchUrl };
 | 
			
		||||
                if (AppTask is SelectEntryTask currentSelectTask)
 | 
			
		||||
                    newTask.ShowUserNotifications = currentSelectTask.ShowUserNotifications;
 | 
			
		||||
 | 
			
		||||
                selectOtherEntry.Click += (sender, e) => {
 | 
			
		||||
                    GroupActivity.Launch(this, newTask, new ActivityLaunchModeRequestCode(0));
 | 
			
		||||
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                if (App.Kp2a.OpenDatabases.Any(db => db.CanWrite))
 | 
			
		||||
                {
 | 
			
		||||
                    createUrlEntry.Visibility = ViewStates.Visible;
 | 
			
		||||
                    createUrlEntry.Click += (sender, e) =>
 | 
			
		||||
                    {
 | 
			
		||||
                        GroupActivity.Launch(this, new CreateEntryThenCloseTask { Url = searchUrl, ShowUserNotifications = (AppTask as SelectEntryTask)?.ShowUserNotifications ?? ShowUserNotificationsMode.Always }, new ActivityLaunchModeRequestCode(0));
 | 
			
		||||
                        Toast.MakeText(this, GetString(Resource.String.select_group_then_add, new Java.Lang.Object[] { GetString(Resource.String.add_entry) }), ToastLength.Long).Show();
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    createUrlEntry.Visibility = ViewStates.Gone;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			
 | 
			
		||||
			View createUrlEntry = FindViewById (Resource.Id.add_url_entry);
 | 
			
		||||
 | 
			
		||||
			if (App.Kp2a.OpenDatabases.Any(db => db.CanWrite))
 | 
			
		||||
			{
 | 
			
		||||
				createUrlEntry.Visibility = ViewStates.Visible;
 | 
			
		||||
				createUrlEntry.Click += (sender, e) =>
 | 
			
		||||
				{
 | 
			
		||||
					GroupActivity.Launch(this, new CreateEntryThenCloseTask { Url = url, ShowUserNotifications = (AppTask as SelectEntryTask)?.ShowUserNotifications ?? ShowUserNotificationsMode.Always }, new ActivityLaunchModeRequestCode(0));
 | 
			
		||||
					Toast.MakeText(this, GetString(Resource.String.select_group_then_add, new Java.Lang.Object[] { GetString(Resource.String.add_entry) }), ToastLength.Long).Show();
 | 
			
		||||
				};
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				createUrlEntry.Visibility = ViewStates.Gone;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			Util.MoveBottomBarButtons(Resource.Id.select_other_entry, Resource.Id.add_url_entry, Resource.Id.bottom_bar, this);
 | 
			
		||||
		}
 | 
			
		||||
@@ -201,6 +236,31 @@ namespace keepass2android
 | 
			
		||||
            return resultsGroup;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public static PwGroup GetSearchResultsForUuid(string uuid)
 | 
			
		||||
        {
 | 
			
		||||
            PwGroup resultsGroup = null;
 | 
			
		||||
            foreach (var db in App.Kp2a.OpenDatabases)
 | 
			
		||||
            {
 | 
			
		||||
                
 | 
			
		||||
                var resultsForThisDb = db.SearchForUuid(uuid);
 | 
			
		||||
                
 | 
			
		||||
                if (resultsGroup == null)
 | 
			
		||||
                {
 | 
			
		||||
                    resultsGroup = resultsForThisDb;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    foreach (var entry in resultsForThisDb.Entries)
 | 
			
		||||
                    {
 | 
			
		||||
                        resultsGroup.AddEntry(entry, false, false);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return resultsGroup;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool OnSearchRequested()
 | 
			
		||||
		{
 | 
			
		||||
			Intent i = new Intent(this, typeof(SearchActivity));
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ namespace keepass2android
 | 
			
		||||
                foreach (ITotpPluginAdapter adapter in _pluginAdapters)
 | 
			
		||||
                {
 | 
			
		||||
                    TotpData totpData = adapter.GetTotpData(
 | 
			
		||||
                        App.Kp2a.LastOpenedEntry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key),
 | 
			
		||||
                        entry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key),
 | 
			
		||||
                            pair => pair.Value.ReadString()), LocaleManager.LocalizedAppContext, false);
 | 
			
		||||
                    if (totpData.IsTotpEntry)
 | 
			
		||||
                    {
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ using Android.OS;
 | 
			
		||||
using Android.Widget;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using KeePassLib;
 | 
			
		||||
using KeePassLib.Security;
 | 
			
		||||
using KeePassLib.Utility;
 | 
			
		||||
@@ -339,7 +340,7 @@ namespace keepass2android
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public virtual void CompleteOnCreateEntryActivity(EntryActivity activity)
 | 
			
		||||
		public virtual void CompleteOnCreateEntryActivity(EntryActivity activity, Thread notifyPluginsOnOpenThread)
 | 
			
		||||
		{
 | 
			
		||||
			activity.StartNotificationsService(false);
 | 
			
		||||
		}
 | 
			
		||||
@@ -453,7 +454,7 @@ namespace keepass2android
 | 
			
		||||
			intent.PutExtra(UrlToSearchKey, UrlToSearchFor);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	    public override void CompleteOnCreateEntryActivity(EntryActivity activity)
 | 
			
		||||
	    public override void CompleteOnCreateEntryActivity(EntryActivity activity, Thread notifyPluginsOnOpenThread)
 | 
			
		||||
	    {
 | 
			
		||||
            if (App.Kp2a.LastOpenedEntry != null)
 | 
			
		||||
	            App.Kp2a.LastOpenedEntry.SearchUrl = UrlToSearchFor;
 | 
			
		||||
@@ -462,18 +463,18 @@ namespace keepass2android
 | 
			
		||||
            //if the database is readonly (or no URL exists), don't offer to modify the URL
 | 
			
		||||
            if ((App.Kp2a.CurrentDb.CanWrite == false) || (String.IsNullOrEmpty(UrlToSearchFor) || keepass2android.ShareUrlResults.GetSearchResultsForUrl(UrlToSearchFor).Entries.Any(e => e == activity.Entry) ))
 | 
			
		||||
            {
 | 
			
		||||
                base.CompleteOnCreateEntryActivity(activity);
 | 
			
		||||
                base.CompleteOnCreateEntryActivity(activity, notifyPluginsOnOpenThread);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            AskAddUrlThenCompleteCreate(activity, UrlToSearchFor);
 | 
			
		||||
            AskAddUrlThenCompleteCreate(activity, UrlToSearchFor, notifyPluginsOnOpenThread);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// brings up a dialog asking the user whether he wants to add the given URL to the entry for automatic finding
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public void AskAddUrlThenCompleteCreate(EntryActivity activity, string url)
 | 
			
		||||
        public void AskAddUrlThenCompleteCreate(EntryActivity activity, string url, Thread notifyPluginsOnOpenThread)
 | 
			
		||||
        {
 | 
			
		||||
            AlertDialog.Builder builder = new AlertDialog.Builder(activity);
 | 
			
		||||
            builder.SetTitle(activity.GetString(Resource.String.AddUrlToEntryDialog_title));
 | 
			
		||||
@@ -482,12 +483,13 @@ namespace keepass2android
 | 
			
		||||
 | 
			
		||||
            builder.SetPositiveButton(activity.GetString(Resource.String.yes), (dlgSender, dlgEvt) =>
 | 
			
		||||
            {
 | 
			
		||||
                activity.AddUrlToEntry(url, (EntryActivity thenActiveActivity) => base.CompleteOnCreateEntryActivity(thenActiveActivity));
 | 
			
		||||
                activity.AddUrlToEntry(url, (EntryActivity thenActiveActivity) => base.CompleteOnCreateEntryActivity(thenActiveActivity, notifyPluginsOnOpenThread
 | 
			
		||||
));
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            builder.SetNegativeButton(activity.GetString(Resource.String.no), (dlgSender, dlgEvt) =>
 | 
			
		||||
            {
 | 
			
		||||
                base.CompleteOnCreateEntryActivity(activity);
 | 
			
		||||
                base.CompleteOnCreateEntryActivity(activity, notifyPluginsOnOpenThread);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            Dialog dialog = builder.Create();
 | 
			
		||||
@@ -495,6 +497,44 @@ namespace keepass2android
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class OpenSpecificEntryTask : SelectEntryTask
 | 
			
		||||
    {
 | 
			
		||||
        public OpenSpecificEntryTask()
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public const String EntryUuidKey = "EntryUuid";
 | 
			
		||||
 | 
			
		||||
        public string EntryUuid
 | 
			
		||||
        {
 | 
			
		||||
            get;
 | 
			
		||||
            set;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void Setup(Bundle b)
 | 
			
		||||
        {
 | 
			
		||||
            base.Setup(b);
 | 
			
		||||
            EntryUuid = b.GetString(EntryUuidKey);
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
        public override IEnumerable<IExtra> Extras
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                foreach (IExtra e in base.Extras)
 | 
			
		||||
                    yield return e;
 | 
			
		||||
                
 | 
			
		||||
                yield return new StringExtra { Key = EntryUuidKey, Value = EntryUuid };
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void LaunchFirstGroupActivity(Activity act)
 | 
			
		||||
        {
 | 
			
		||||
            ShareUrlResults.Launch(act, this, new ActivityLaunchModeRequestCode(0));
 | 
			
		||||
        }
 | 
			
		||||
		
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public enum ShowUserNotificationsMode
 | 
			
		||||
    {
 | 
			
		||||
@@ -545,7 +585,7 @@ namespace keepass2android
 | 
			
		||||
            }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void CompleteOnCreateEntryActivity(EntryActivity activity)
 | 
			
		||||
		public override void CompleteOnCreateEntryActivity(EntryActivity activity, Thread notifyPluginsOnOpenThread)
 | 
			
		||||
		{
 | 
			
		||||
		    Context ctx = activity;
 | 
			
		||||
		    if (ctx == null)
 | 
			
		||||
@@ -563,9 +603,11 @@ namespace keepass2android
 | 
			
		||||
				CopyToClipboardService.CancelNotifications(activity);
 | 
			
		||||
			}
 | 
			
		||||
			if (CloseAfterCreate)
 | 
			
		||||
			{
 | 
			
		||||
				//close
 | 
			
		||||
				activity.CloseAfterTaskComplete();	
 | 
			
		||||
            {
 | 
			
		||||
				//give plugins and TOTP time to do their work:
 | 
			
		||||
                notifyPluginsOnOpenThread.Join(TimeSpan.FromSeconds(1));
 | 
			
		||||
                //close
 | 
			
		||||
                activity.CloseAfterTaskComplete();	
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -729,10 +771,10 @@ namespace keepass2android
 | 
			
		||||
			//no need to call Finish here, that's done in EntryEditActivity ("closeOrShowError")	
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		public override void CompleteOnCreateEntryActivity(EntryActivity activity)
 | 
			
		||||
		public override void CompleteOnCreateEntryActivity(EntryActivity activity, Thread notifyPluginsOnOpenThread)
 | 
			
		||||
		{
 | 
			
		||||
			//if the user selects an entry before creating the new one, we're not closing the app
 | 
			
		||||
			base.CompleteOnCreateEntryActivity(activity);
 | 
			
		||||
			base.CompleteOnCreateEntryActivity(activity, notifyPluginsOnOpenThread);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ using AndroidX.AutoFill.Inline;
 | 
			
		||||
using AndroidX.AutoFill.Inline.V1;
 | 
			
		||||
using Java.Util.Concurrent.Atomic;
 | 
			
		||||
using keepass2android.services.AutofillBase.model;
 | 
			
		||||
using KeePassLib;
 | 
			
		||||
using Kp2aAutofillParser;
 | 
			
		||||
 | 
			
		||||
namespace keepass2android.services.AutofillBase
 | 
			
		||||
@@ -29,7 +30,7 @@ namespace keepass2android.services.AutofillBase
 | 
			
		||||
        PendingIntent GetAuthPendingIntentForResponse(Context context, string query, string queryDomain, string queryPackage,
 | 
			
		||||
            bool isManualRequest, bool autoReturnFromQuery, AutofillServiceBase.DisplayWarning warning);
 | 
			
		||||
 | 
			
		||||
        PendingIntent GetAuthPendingIntentForWarning(Context context, string query, string queryDomain, string queryPackage, AutofillServiceBase.DisplayWarning warning);
 | 
			
		||||
        PendingIntent GetAuthPendingIntentForWarning(Context context, PwUuid entryUuid, AutofillServiceBase.DisplayWarning warning);
 | 
			
		||||
 | 
			
		||||
        PendingIntent GetDisablePendingIntentForResponse(Context context, string query, 
 | 
			
		||||
            bool isManualRequest, bool isDisable);
 | 
			
		||||
@@ -262,33 +263,42 @@ namespace keepass2android.services.AutofillBase
 | 
			
		||||
        {
 | 
			
		||||
            List<Dataset> result = new List<Dataset>();
 | 
			
		||||
            Kp2aLog.Log("AF: BuildEntryDatasets");
 | 
			
		||||
            var suggestedEntries = GetSuggestedEntries(query).ToDictionary(e => e.DatasetName, e => e);
 | 
			
		||||
            Dictionary<PwEntryOutput, FilledAutofillFieldCollection<ViewNodeInputField>> suggestedEntries = GetSuggestedEntries(query);
 | 
			
		||||
            Kp2aLog.Log("AF: BuildEntryDatasets found " + suggestedEntries.Count + " entries");
 | 
			
		||||
            
 | 
			
		||||
            int count = 0;
 | 
			
		||||
            foreach (var filledAutofillFieldCollection in suggestedEntries.Values)
 | 
			
		||||
 | 
			
		||||
            var totpHelper = new Kp2aTotp();
 | 
			
		||||
 | 
			
		||||
            foreach (var kvp in suggestedEntries)
 | 
			
		||||
            {
 | 
			
		||||
                var filledAutofillFieldCollection = kvp.Value;
 | 
			
		||||
                PwEntryOutput entry = kvp.Key;
 | 
			
		||||
 | 
			
		||||
                if (filledAutofillFieldCollection == null)
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                var inlinePresentationSpec = AutofillHelper.ExtractSpec(inlinePresentationSpecs, count);
 | 
			
		||||
 | 
			
		||||
                if (warning == DisplayWarning.None)
 | 
			
		||||
                if ((warning == DisplayWarning.None)
 | 
			
		||||
                    && (totpHelper.TryGetAdapter(entry) == null))
 | 
			
		||||
                {
 | 
			
		||||
          
 | 
			
		||||
                    //no special dataset, we can immediately return the field collection
 | 
			
		||||
                    FilledAutofillFieldCollection<ViewNodeInputField> partitionData =
 | 
			
		||||
                        AutofillHintsHelper.FilterForPartition(filledAutofillFieldCollection, parser.AutofillFields.FocusedAutofillCanonicalHints);
 | 
			
		||||
 | 
			
		||||
                    Kp2aLog.Log("AF: Add dataset");
 | 
			
		||||
 | 
			
		||||
                    result.Add(AutofillHelper.NewDataset(this, parser.AutofillFields, partitionData, IntentBuilder, 
 | 
			
		||||
                    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)
 | 
			
		||||
 | 
			
		||||
                    //return an "auth" dataset (actually for just warning the user in case domain/package dont match and/or to make sure that we open the EntryActivity,
 | 
			
		||||
                    // thus opening the entry notification in case of TOTP)
 | 
			
		||||
                    PendingIntent pendingIntent =
 | 
			
		||||
                        IntentBuilder.GetAuthPendingIntentForWarning(this, query, queryDomain, queryPackage, warning);
 | 
			
		||||
                        IntentBuilder.GetAuthPendingIntentForWarning(this, entry.Uuid, warning);
 | 
			
		||||
                    var datasetName = filledAutofillFieldCollection.DatasetName;
 | 
			
		||||
                    if (datasetName == null)
 | 
			
		||||
                    {
 | 
			
		||||
@@ -320,7 +330,7 @@ namespace keepass2android.services.AutofillBase
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected abstract List<FilledAutofillFieldCollection<ViewNodeInputField>> GetSuggestedEntries(string query);
 | 
			
		||||
        protected abstract Dictionary<PwEntryOutput, FilledAutofillFieldCollection<ViewNodeInputField>> GetSuggestedEntries(string query);
 | 
			
		||||
 | 
			
		||||
        public enum DisplayWarning
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@ namespace keepass2android.services.AutofillBase
 | 
			
		||||
    {
 | 
			
		||||
        protected Intent ReplyIntent;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public static string ExtraUuidString => "EXTRA_UUID_STRING";
 | 
			
		||||
        public static string ExtraQueryString => "EXTRA_QUERY_STRING";
 | 
			
		||||
        public static string ExtraQueryPackageString => "EXTRA_QUERY_PACKAGE_STRING";
 | 
			
		||||
        public static string ExtraQueryDomainString => "EXTRA_QUERY_DOMAIN_STRING";
 | 
			
		||||
@@ -50,9 +50,10 @@ namespace keepass2android.services.AutofillBase
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            string requestedUrl = Intent.GetStringExtra(ExtraQueryString);
 | 
			
		||||
            if (requestedUrl == null)
 | 
			
		||||
            string requestedUuid = Intent.GetStringExtra(ExtraUuidString);
 | 
			
		||||
            if (requestedUrl == null && requestedUuid == null)
 | 
			
		||||
            {
 | 
			
		||||
                Kp2aLog.Log("ChooseForAutofillActivityBase: no requestedUrl ");
 | 
			
		||||
                Kp2aLog.Log("ChooseForAutofillActivityBase: no requestedUrl and no requestedUuid");
 | 
			
		||||
                Toast.MakeText(this, "Cannot execute query for null.", ToastLength.Long).Show();
 | 
			
		||||
                RestartApp();
 | 
			
		||||
                return;
 | 
			
		||||
@@ -134,18 +135,30 @@ namespace keepass2android.services.AutofillBase
 | 
			
		||||
        private void Proceed()
 | 
			
		||||
        {
 | 
			
		||||
            string requestedUrl = Intent.GetStringExtra(ExtraQueryString);
 | 
			
		||||
            string requestedUuid = Intent.GetStringExtra(ExtraUuidString);
 | 
			
		||||
 | 
			
		||||
            var i = GetQueryIntent(requestedUrl, Intent.GetBooleanExtra(ExtraAutoReturnFromQuery, true), Intent.GetBooleanExtra(ExtraUseLastOpenedEntry, false));
 | 
			
		||||
            if (i == null)
 | 
			
		||||
            if (requestedUuid != null)
 | 
			
		||||
            {
 | 
			
		||||
                //GetQueryIntent returns null if no query is required
 | 
			
		||||
                ReturnSuccess();
 | 
			
		||||
                var i = GetOpenEntryIntent(requestedUuid);
 | 
			
		||||
                StartActivityForResult(i, RequestCodeQuery);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                StartActivityForResult(i, RequestCodeQuery);
 | 
			
		||||
            {
 | 
			
		||||
                var i = GetQueryIntent(requestedUrl, Intent.GetBooleanExtra(ExtraAutoReturnFromQuery, true), Intent.GetBooleanExtra(ExtraUseLastOpenedEntry, false));
 | 
			
		||||
                if (i == null)
 | 
			
		||||
                {
 | 
			
		||||
                    //GetQueryIntent returns null if no query is required
 | 
			
		||||
                    ReturnSuccess();
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                    StartActivityForResult(i, RequestCodeQuery);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected abstract Intent GetQueryIntent(string requestedUrl, bool autoReturnFromQuery, bool useLastOpenedEntry);
 | 
			
		||||
        protected abstract Intent GetOpenEntryIntent(string entryUuid);
 | 
			
		||||
 | 
			
		||||
        protected void RestartApp()
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -41,6 +41,15 @@ namespace keepass2android.services.Kp2aAutofill
 | 
			
		||||
            return i;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override Intent GetOpenEntryIntent(string entryUuid)
 | 
			
		||||
        {
 | 
			
		||||
            Intent i = new Intent(this, typeof(SelectCurrentDbActivity));
 | 
			
		||||
            //don't show user notifications when an entry is opened.
 | 
			
		||||
            var task = new OpenSpecificEntryTask() { EntryUuid = entryUuid, ShowUserNotifications = ShowUserNotificationsMode.WhenTotp, ActivateKeyboard = false};
 | 
			
		||||
            task.ToIntent(i);
 | 
			
		||||
            return i;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override Result ExpectedActivityResult => KeePass.ExitCloseAfterTaskComplete;
 | 
			
		||||
 | 
			
		||||
        protected override FilledAutofillFieldCollection<ViewNodeInputField> GetDataset()
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ using System.Linq;
 | 
			
		||||
using Android;
 | 
			
		||||
using Android.App;
 | 
			
		||||
using Android.Content;
 | 
			
		||||
using Android.Preferences;
 | 
			
		||||
using Android.Runtime;
 | 
			
		||||
using keepass2android.services.AutofillBase;
 | 
			
		||||
using keepass2android.services.AutofillBase.model;
 | 
			
		||||
@@ -34,24 +35,29 @@ namespace keepass2android.services
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override List<FilledAutofillFieldCollection<ViewNodeInputField>> GetSuggestedEntries(string query)
 | 
			
		||||
        protected override Dictionary<PwEntryOutput, FilledAutofillFieldCollection<ViewNodeInputField>> GetSuggestedEntries(string query)
 | 
			
		||||
        {
 | 
			
		||||
            if (!App.Kp2a.DatabaseIsUnlocked)
 | 
			
		||||
                return new List<FilledAutofillFieldCollection<ViewNodeInputField>>();
 | 
			
		||||
                return new Dictionary<PwEntryOutput, FilledAutofillFieldCollection<ViewNodeInputField>>();
 | 
			
		||||
            var foundEntries = (ShareUrlResults.GetSearchResultsForUrl(query)?.Entries ?? new PwObjectList<PwEntry>())
 | 
			
		||||
                .Select(e => new PwEntryOutput(e, App.Kp2a.FindDatabaseForElement(e)))
 | 
			
		||||
                .ToList();
 | 
			
		||||
 | 
			
		||||
            if (App.Kp2a.LastOpenedEntry?.SearchUrl == query)
 | 
			
		||||
            {
 | 
			
		||||
                foundEntries.Clear();
 | 
			
		||||
                foundEntries.Add(App.Kp2a.LastOpenedEntry);
 | 
			
		||||
                foundEntries.Add(App.Kp2a.LastOpenedEntry?.Entry);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //it seems like at least with Firefox we can have at most 3 datasets. Reserve space for the disable/enable dataset and the "fill with KP2A" which allows to select another item
 | 
			
		||||
            //so take only 1:
 | 
			
		||||
            return foundEntries.Take(1).Select(e => ChooseForAutofillActivity.GetFilledAutofillFieldCollectionFromEntry(e, this))
 | 
			
		||||
                .ToList();
 | 
			
		||||
            int numDisableDatasets = 0;
 | 
			
		||||
            if (!PreferenceManager.GetDefaultSharedPreferences(this)
 | 
			
		||||
                    .GetBoolean(GetString(Resource.String.NoAutofillDisabling_key), false))
 | 
			
		||||
                numDisableDatasets = 1;
 | 
			
		||||
 | 
			
		||||
                //it seems like at least with Firefox we can have at most 3 datasets. Reserve space for the disable dataset and the "fill with KP2A" which allows to select another item
 | 
			
		||||
                return foundEntries.Take(2-numDisableDatasets)
 | 
			
		||||
                    .Select(e => new PwEntryOutput(e, App.Kp2a.FindDatabaseForElement(e)))
 | 
			
		||||
                    .ToDictionary(e => e,
 | 
			
		||||
                                e => ChooseForAutofillActivity.GetFilledAutofillFieldCollectionFromEntry(e, this));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void HandleSaveRequest(StructureParser parser, StructureParser.AutofillTargetId query)
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ using Android.Views;
 | 
			
		||||
using Android.Widget;
 | 
			
		||||
using keepass2android.services.AutofillBase;
 | 
			
		||||
using keepass2android.services.Kp2aAutofill;
 | 
			
		||||
using KeePassLib;
 | 
			
		||||
 | 
			
		||||
namespace keepass2android.services
 | 
			
		||||
{
 | 
			
		||||
@@ -29,16 +30,14 @@ namespace keepass2android.services
 | 
			
		||||
            return PendingIntent.GetActivity(context, _pendingIntentRequestCode++, intent, Util.AddMutabilityFlag(PendingIntentFlags.CancelCurrent, PendingIntentFlags.Mutable));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public PendingIntent GetAuthPendingIntentForWarning(Context context, string query, string queryDomain, string queryPackage,
 | 
			
		||||
        public PendingIntent GetAuthPendingIntentForWarning(Context context,PwUuid entryUuid,
 | 
			
		||||
            AutofillServiceBase.DisplayWarning warning)
 | 
			
		||||
        {
 | 
			
		||||
            Intent intent = new Intent(context, typeof(ChooseForAutofillActivity));
 | 
			
		||||
            intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryString, query);
 | 
			
		||||
            intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryDomainString, queryDomain);
 | 
			
		||||
            intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryPackageString, queryPackage);
 | 
			
		||||
            intent.PutExtra(ChooseForAutofillActivityBase.ExtraUuidString, entryUuid.ToHexString());
 | 
			
		||||
            intent.PutExtra(ChooseForAutofillActivityBase.ExtraDisplayWarning, (int)warning);
 | 
			
		||||
            intent.PutExtra(ChooseForAutofillActivityBase.ExtraUseLastOpenedEntry, true);
 | 
			
		||||
            return PendingIntent.GetActivity(context, _pendingIntentRequestCode++, intent, Util.AddMutabilityFlag(PendingIntentFlags.CancelCurrent, PendingIntentFlags.Immutable));
 | 
			
		||||
            return PendingIntent.GetActivity(context, _pendingIntentRequestCode++, intent, Util.AddMutabilityFlag(PendingIntentFlags.CancelCurrent, PendingIntentFlags.Mutable));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public PendingIntent GetDisablePendingIntentForResponse(Context context, string query,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user