diff --git a/src/Kp2aBusinessLogic/BlockingOperationRunner.cs b/src/Kp2aBusinessLogic/BlockingOperationRunner.cs
index 377eec45..eff116c6 100644
--- a/src/Kp2aBusinessLogic/BlockingOperationRunner.cs
+++ b/src/Kp2aBusinessLogic/BlockingOperationRunner.cs
@@ -45,6 +45,8 @@ namespace keepass2android
}
}
+ public ProgressUiAsStatusLoggerAdapter StatusLogger => _statusLogger;
+
private BackgroundOperationRunner()
{
//private constructor
@@ -77,7 +79,6 @@ namespace keepass2android
if (!_taskQueue.Any())
{
_thread = null;
- _currentlyRunningTask = null;
_statusLogger.EndLogging();
break;
}
@@ -86,7 +87,18 @@ namespace keepass2android
_currentlyRunningTask = _taskQueue.Dequeue();
}
}
+
+ var originalFinishedHandler = _currentlyRunningTask.operationFinishedHandler;
+ _currentlyRunningTask.operationFinishedHandler = new ActionOnOperationFinished(app, (
+ (success, message, context) =>
+ {
+ _currentlyRunningTask = null;
+ }), originalFinishedHandler);
_currentlyRunningTask.Run();
+ while (_currentlyRunningTask != null)
+ {
+ Thread.Sleep(100);
+ }
}
});
@@ -248,13 +260,7 @@ namespace keepass2android
get { return _activeActivity; }
private set
{
- if (_activeActivity != null && _activeActivity != _previouslyActiveContext)
- {
- _previouslyActiveContext = _activeActivity;
-
-
- }
- _activeActivity = value;
+ _activeActivity = value;
if (_activeActivity != null)
{
@@ -264,18 +270,12 @@ namespace keepass2android
}
}
- public Context PreviouslyActiveContext
- {
- get { return _previouslyActiveContext; }
-
- }
-
- private readonly Handler _handler;
+ private readonly Handler _handler;
private readonly OperationWithFinishHandler _task;
private IProgressDialog _progressDialog;
private readonly IKp2aApp _app;
private Java.Lang.Thread _thread;
- private Context _activeActivity, _previouslyActiveContext;
+ private Context _activeActivity;
private ProgressDialogStatusLogger _progressDialogStatusLogger;
public BlockingOperationRunner(IKp2aApp app, OperationWithFinishHandler task)
diff --git a/src/Kp2aBusinessLogic/database/SynchronizeCachedDatabase.cs b/src/Kp2aBusinessLogic/database/SynchronizeCachedDatabase.cs
index 1d5707fd..552cc021 100644
--- a/src/Kp2aBusinessLogic/database/SynchronizeCachedDatabase.cs
+++ b/src/Kp2aBusinessLogic/database/SynchronizeCachedDatabase.cs
@@ -82,6 +82,8 @@ namespace keepass2android
}
_saveDb = null;
}), _app.CurrentDb, false, remoteData);
+ _saveDb.SetStatusLogger(StatusLogger);
+ _saveDb.DoNotSetStatusLoggerMessage = true; //Keep "sync db" as main message
_saveDb.SyncInBackground = false;
_saveDb.Run();
diff --git a/src/Kp2aBusinessLogic/database/edit/ActionOnOperationFinished.cs b/src/Kp2aBusinessLogic/database/edit/ActionOnOperationFinished.cs
index 373d1bb8..c17c36de 100644
--- a/src/Kp2aBusinessLogic/database/edit/ActionOnOperationFinished.cs
+++ b/src/Kp2aBusinessLogic/database/edit/ActionOnOperationFinished.cs
@@ -38,9 +38,6 @@ namespace keepass2android
_actionToPerform = actionToPerform;
}
- //if set to true, the previously active active will be passed to ActionToPerformOnFinish instead null if no activity is on foreground
- public bool AllowInactiveActivity { get; set; }
-
public override void Run()
{
if (Message == null)
diff --git a/src/Kp2aBusinessLogic/database/edit/SaveDB.cs b/src/Kp2aBusinessLogic/database/edit/SaveDB.cs
index b8f10d19..41710977 100644
--- a/src/Kp2aBusinessLogic/database/edit/SaveDB.cs
+++ b/src/Kp2aBusinessLogic/database/edit/SaveDB.cs
@@ -41,6 +41,8 @@ namespace keepass2android
private readonly bool _dontSave;
private bool requiresSubsequentSync = false; //if true, we need to sync the file after saving.
+ public bool DoNotSetStatusLoggerMessage = false;
+
///
/// stream for reading the data from the original file. If this is set to a non-null value, we know we need to sync
///
@@ -104,9 +106,12 @@ namespace keepass2android
if (ShowDatabaseIocInStatus)
message += " (" + _app.GetFileStorage(_db.Ioc).GetDisplayName(_db.Ioc) + ")";
- StatusLogger.UpdateMessage(message);
-
- IOConnectionInfo ioc = _db.Ioc;
+ if (!DoNotSetStatusLoggerMessage)
+ {
+ StatusLogger.UpdateMessage(message);
+ }
+
+ IOConnectionInfo ioc = _db.Ioc;
IFileStorage fileStorage = _app.GetFileStorage(ioc);
if (SyncInBackground && fileStorage is IOfflineSwitchable offlineSwitchable)
diff --git a/src/keepass2android-app/GroupBaseActivity.cs b/src/keepass2android-app/GroupBaseActivity.cs
index 365df0d0..036a6b29 100644
--- a/src/keepass2android-app/GroupBaseActivity.cs
+++ b/src/keepass2android-app/GroupBaseActivity.cs
@@ -1305,7 +1305,7 @@ namespace keepass2android
{
if (Success)
{
- ((GroupBaseActivity)ActiveContext)?.RefreshIfDirty();
+ (ActiveContext as GroupBaseActivity)?.RefreshIfDirty();
}
else
{
@@ -1325,7 +1325,7 @@ namespace keepass2android
{
if (Success)
{
- ((GroupBaseActivity)ActiveContext)?.RefreshIfDirty();
+ (ActiveContext as GroupBaseActivity)?.RefreshIfDirty();
}
else
{
diff --git a/src/keepass2android-app/Resources/values/strings.xml b/src/keepass2android-app/Resources/values/strings.xml
index e012dd2a..a43e9497 100644
--- a/src/keepass2android-app/Resources/values/strings.xml
+++ b/src/keepass2android-app/Resources/values/strings.xml
@@ -1255,5 +1255,5 @@
Note: You have enabled App - Password access - Autofill-Service - Autofill for TOTP entries. This can cause this window to show when you open an entry with a TOTP.
Note: You have enabled App - Security - Use built-in keyboard inside Keepass2Android. This can cause this window to show when you open the app or edit an entry.
Note: You have enabled App - Security - Password access - Keyboard switching - Switch keyboard. This can cause this window to show when you search for an entry from the browser.
-
+ User interaction required. Please open the app.
\ No newline at end of file
diff --git a/src/keepass2android-app/app/App.cs b/src/keepass2android-app/app/App.cs
index 7dc66fd7..8db785a4 100644
--- a/src/keepass2android-app/app/App.cs
+++ b/src/keepass2android-app/app/App.cs
@@ -17,6 +17,7 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
using System;
using System.Collections.Generic;
+using System.ComponentModel.Design;
using System.IO;
using System.Linq;
using System.Net.Security;
@@ -46,6 +47,7 @@ using keepass2android;
using keepass2android.Utils;
using KeePassLib.Interfaces;
using KeePassLib.Utility;
+using AlertDialog = AndroidX.AppCompat.App.AlertDialog;
using Message = keepass2android.Utils.Message;
#if !NoNet
#if !EXCLUDE_JAVAFILESTORAGE
@@ -480,6 +482,8 @@ namespace keepass2android
// Whether the app is currently showing a dialog that requires user input, like a yesNoCancel dialog
private bool _isShowingUserInputDialog = false;
private IMessagePresenter? _messagePresenter;
+ private YesNoCancelQuestion? _currentlyPendingYesNoCancelQuestion = null;
+ private Context _activeContext;
private void AskForReload(Activity activity, Action actionOnResult)
{
@@ -591,92 +595,142 @@ namespace keepass2android
AskYesNoCancel(titleKey, messageKey, yesString, noString, yesHandler, noHandler, cancelHandler, null, messageSuffix);
}
- public void AskYesNoCancel(UiStringKey titleKey, UiStringKey messageKey,
+ class YesNoCancelQuestion
+ {
+ private AlertDialog? _dialog;
+ public UiStringKey TitleKey { get; set; }
+ public UiStringKey MessageKey { get; set; }
+ public UiStringKey YesString { get; set; }
+ public UiStringKey NoString { get; set; }
+ public EventHandler? YesHandler { get; set; }
+ public EventHandler? NoHandler { get; set; }
+ public EventHandler? CancelHandler { get; set; }
+ public EventHandler DismissHandler { get; set; }
+ public string MessageSuffix { get; set; }
+
+ public bool TryShow(IKp2aApp app, Action onUserInputDialogClose, Action onUserInputDialogShow)
+ {
+ if (app.ActiveContext is Activity activity)
+ {
+ Handler handler = new Handler(Looper.MainLooper);
+ handler.Post(() =>
+ {
+ if (_dialog is { IsShowing: true })
+ {
+ _dialog.Dismiss();
+ _dialog = null;
+ }
+
+ MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
+ builder.SetTitle(app.GetResourceString(TitleKey));
+
+ builder.SetMessage(app.GetResourceString(MessageKey) +
+ (MessageSuffix != "" ? " " + MessageSuffix : ""));
+
+ // _____handlerWithShow are wrappers around given handlers to update _isSHowingYesNoCancelDialog
+ // and to show progress dialog after yesNoCancel dialog is closed
+ EventHandler yesHandlerWithShow = (sender, args) =>
+ {
+ onUserInputDialogClose();
+ YesHandler.Invoke(sender, args);
+ };
+ string yesText = app.GetResourceString(YesString);
+ builder.SetPositiveButton(yesText, yesHandlerWithShow);
+ string noText = "";
+ if (NoHandler != null)
+ {
+ EventHandler noHandlerWithShow = (sender, args) =>
+ {
+ onUserInputDialogClose();
+ NoHandler.Invoke(sender, args);
+ };
+
+ noText = app.GetResourceString(NoString);
+ builder.SetNegativeButton(noText, noHandlerWithShow);
+ }
+
+ string cancelText = "";
+ if (CancelHandler != null)
+ {
+ EventHandler cancelHandlerWithShow = (sender, args) =>
+ {
+ onUserInputDialogClose();
+ CancelHandler.Invoke(sender, args);
+ };
+
+ cancelText = App.Context.GetString(Android.Resource.String.Cancel);
+ builder.SetNeutralButton(cancelText,
+ cancelHandlerWithShow);
+ }
+
+ _dialog = builder.Create();
+ if (DismissHandler != null)
+ {
+ _dialog.SetOnDismissListener(new Util.DismissListener(() =>
+ {
+ onUserInputDialogClose();
+ DismissHandler(_dialog, EventArgs.Empty);
+ }));
+ }
+
+ onUserInputDialogShow();
+ try
+ {
+ _dialog.Show();
+ }
+ catch (Exception e)
+ {
+ Kp2aLog.LogUnexpectedError(e);
+ }
+
+
+ if (yesText.Length + noText.Length + cancelText.Length >= 20)
+ {
+ try
+ {
+ Button button = _dialog.GetButton((int)DialogButtonType.Positive);
+ LinearLayout linearLayout = (LinearLayout)button.Parent;
+ linearLayout.Orientation = Orientation.Vertical;
+ }
+ catch (Exception e)
+ {
+ Kp2aLog.LogUnexpectedError(e);
+ }
+
+ }
+ });
+ return true;
+ }
+ else
+ {
+ BackgroundOperationRunner.Instance.StatusLogger?.UpdateSubMessage(App.Context.GetString(Resource.String.user_interaction_required));
+ return false;
+ }
+ }
+ }
+
+ public void AskYesNoCancel(UiStringKey titleKey, UiStringKey messageKey,
UiStringKey yesString, UiStringKey noString,
EventHandler yesHandler,
EventHandler noHandler,
EventHandler cancelHandler,
EventHandler dismissHandler,string messageSuffix = "")
{
- Handler handler = new Handler(Looper.MainLooper);
- handler.Post(() =>
- {
- MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ActiveContext);
- builder.SetTitle(GetResourceString(titleKey));
-
- builder.SetMessage(GetResourceString(messageKey) + (messageSuffix != "" ? " " + messageSuffix : ""));
-
- // _____handlerWithShow are wrappers around given handlers to update _isSHowingYesNoCancelDialog
- // and to show progress dialog after yesNoCancel dialog is closed
- EventHandler yesHandlerWithShow = (sender, args) =>
- {
- OnUserInputDialogClose();
- yesHandler.Invoke(sender, args);
- };
- string yesText = GetResourceString(yesString);
- builder.SetPositiveButton(yesText, yesHandlerWithShow);
- string noText = "";
- if (noHandler != null)
- {
- EventHandler noHandlerWithShow = (sender, args) =>
- {
- OnUserInputDialogClose();
- noHandler.Invoke(sender, args);
- };
-
- noText = GetResourceString(noString);
- builder.SetNegativeButton(noText, noHandlerWithShow);
- }
- string cancelText = "";
- if (cancelHandler != null)
- {
- EventHandler cancelHandlerWithShow = (sender, args) =>
- {
- OnUserInputDialogClose();
- cancelHandler.Invoke(sender, args);
- };
-
- cancelText = App.Context.GetString(Android.Resource.String.Cancel);
- builder.SetNeutralButton(cancelText,
- cancelHandlerWithShow);
- }
-
- var dialog = builder.Create();
- if (dismissHandler != null)
- {
- dialog.SetOnDismissListener(new Util.DismissListener(() => {
- OnUserInputDialogClose();
- dismissHandler(dialog, EventArgs.Empty);
- }));
- }
-
- OnUserInputDialogShow();
- try
- {
- dialog.Show();
- }
- catch (Exception e)
- {
- Kp2aLog.LogUnexpectedError(e);
- }
-
-
- if (yesText.Length + noText.Length + cancelText.Length >= 20)
- {
- try
- {
- Button button = dialog.GetButton((int)DialogButtonType.Positive);
- LinearLayout linearLayout = (LinearLayout)button.Parent;
- linearLayout.Orientation = Orientation.Vertical;
- }
- catch (Exception e)
- {
- Kp2aLog.LogUnexpectedError(e);
- }
-
- }
- }
- );
+ _currentlyPendingYesNoCancelQuestion = new YesNoCancelQuestion()
+ {
+ TitleKey = titleKey,
+ MessageKey = messageKey,
+ YesString = yesString,
+ NoString = noString,
+ YesHandler = yesHandler,
+ NoHandler = noHandler,
+ CancelHandler = cancelHandler,
+ DismissHandler = dismissHandler,
+ MessageSuffix = messageSuffix
+ };
+
+ _currentlyPendingYesNoCancelQuestion.TryShow(this, OnUserInputDialogClose, OnUserInputDialogShow);
+
}
///
@@ -718,7 +772,9 @@ namespace keepass2android
private void OnUserInputDialogClose()
{
_isShowingUserInputDialog = false;
- ShowAllActiveProgressDialogs();
+ _currentlyPendingYesNoCancelQuestion = null;
+
+ ShowAllActiveProgressDialogs();
}
public Handler UiThreadHandler
@@ -1369,7 +1425,15 @@ namespace keepass2android
}
- public Context ActiveContext { get; set; }
+ public Context ActiveContext
+ {
+ get => _activeContext;
+ set
+ {
+ _activeContext = value;
+ _currentlyPendingYesNoCancelQuestion?.TryShow(this, OnUserInputDialogClose, OnUserInputDialogClose);
+ }
+ }
}