implement UI updates after background sync for Group activity and Entry activity
This commit is contained in:
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.Text;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using KeePassLib.Serialization;
|
||||
using keepass2android.Io;
|
||||
using KeePass.Util;
|
||||
@@ -12,9 +13,8 @@ namespace keepass2android
|
||||
{
|
||||
public class SynchronizeCachedDatabase: OperationWithFinishHandler
|
||||
{
|
||||
private readonly Context _context;
|
||||
private readonly IKp2aApp _app;
|
||||
private SaveDb _saveDb;
|
||||
|
||||
|
||||
public SynchronizeCachedDatabase(IKp2aApp app, OnOperationFinishedHandler operationFinishedHandler)
|
||||
: base(app, operationFinishedHandler)
|
||||
@@ -70,7 +70,7 @@ namespace keepass2android
|
||||
)
|
||||
{
|
||||
//conflict! need to merge
|
||||
_saveDb = new SaveDb(_app, new ActionOnOperationFinished(_app, (success, result, activity) =>
|
||||
var _saveDb = new SaveDb(_app, new ActionOnOperationFinished(_app, (success, result, activity) =>
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
@@ -80,7 +80,6 @@ namespace keepass2android
|
||||
{
|
||||
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
|
||||
}
|
||||
_saveDb = null;
|
||||
}), _app.CurrentDb, false, remoteData);
|
||||
_saveDb.SetStatusLogger(StatusLogger);
|
||||
_saveDb.DoNotSetStatusLoggerMessage = true; //Keep "sync db" as main message
|
||||
@@ -93,10 +92,32 @@ namespace keepass2android
|
||||
}
|
||||
else
|
||||
{
|
||||
//only the remote file was modified -> reload database.
|
||||
//note: it's best to lock the database and do a complete reload here (also better for UI consistency in case something goes wrong etc.)
|
||||
_app.TriggerReload(_context, (bool result) => Finish(result));
|
||||
}
|
||||
//only the remote file was modified -> reload database.
|
||||
var onFinished = new ActionOnOperationFinished(_app, (success, result, activity) =>
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
Finish(false, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
new Handler(Looper.MainLooper).Post(() =>
|
||||
{
|
||||
_app.CurrentDb.UpdateGlobals();
|
||||
|
||||
_app.MarkAllGroupsAsDirty();
|
||||
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
var _loadDb = new LoadDb(_app, ioc, Task.FromResult(remoteData), _app.CurrentDb.KpDatabase.MasterKey, null, onFinished, true, false);
|
||||
_loadDb.SetStatusLogger(StatusLogger);
|
||||
_loadDb.DoNotSetStatusLoggerMessage = true; //Keep "sync db" as main message
|
||||
_loadDb.SyncInBackground = false;
|
||||
_loadDb.Run();
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -124,10 +145,5 @@ namespace keepass2android
|
||||
|
||||
}
|
||||
|
||||
public void JoinWorkerThread()
|
||||
{
|
||||
if (_saveDb != null)
|
||||
_saveDb.JoinWorkerThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -35,12 +35,15 @@ namespace keepass2android
|
||||
private readonly IOConnectionInfo _ioc;
|
||||
private readonly Task<MemoryStream> _databaseData;
|
||||
private readonly CompositeKey _compositeKey;
|
||||
private readonly string _keyfileOrProvider;
|
||||
private readonly string? _keyfileOrProvider;
|
||||
private readonly IKp2aApp _app;
|
||||
private readonly bool _rememberKeyfile;
|
||||
IDatabaseFormat _format;
|
||||
|
||||
public LoadDb(Activity activity, IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey, String keyfileOrProvider, OnOperationFinishedHandler operationFinishedHandler, bool updateLastUsageTimestamp, bool makeCurrent): base(app, operationFinishedHandler)
|
||||
|
||||
public bool DoNotSetStatusLoggerMessage = false;
|
||||
public bool SyncInBackground { get; set; }
|
||||
|
||||
public LoadDb(IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey, String keyfileOrProvider, OnOperationFinishedHandler operationFinishedHandler, bool updateLastUsageTimestamp, bool makeCurrent): base(app, operationFinishedHandler)
|
||||
{
|
||||
_app = app;
|
||||
_ioc = ioc;
|
||||
@@ -49,8 +52,9 @@ namespace keepass2android
|
||||
_keyfileOrProvider = keyfileOrProvider;
|
||||
_updateLastUsageTimestamp = updateLastUsageTimestamp;
|
||||
_makeCurrent = makeCurrent;
|
||||
_rememberKeyfile = app.GetBooleanPreference(PreferenceKey.remember_keyfile);
|
||||
}
|
||||
_rememberKeyfile = app.GetBooleanPreference(PreferenceKey.remember_keyfile);
|
||||
SyncInBackground = _app.SyncInBackgroundPreference;
|
||||
}
|
||||
|
||||
protected bool success = false;
|
||||
private bool _updateLastUsageTimestamp;
|
||||
@@ -62,15 +66,22 @@ namespace keepass2android
|
||||
{
|
||||
try
|
||||
{
|
||||
//make sure the file data is stored in the recent files list even if loading fails
|
||||
SaveFileData(_ioc, _keyfileOrProvider);
|
||||
if (_keyfileOrProvider != null)
|
||||
{
|
||||
//make sure the file data is stored in the recent files list even if loading fails
|
||||
SaveFileData(_ioc, _keyfileOrProvider);
|
||||
}
|
||||
|
||||
var fileStorage = _app.GetFileStorage(_ioc);
|
||||
|
||||
bool requiresSubsequentSync = false;
|
||||
|
||||
|
||||
StatusLogger.UpdateMessage(UiStringKey.loading_database);
|
||||
if (!DoNotSetStatusLoggerMessage)
|
||||
{
|
||||
StatusLogger.UpdateMessage(UiStringKey.loading_database);
|
||||
}
|
||||
|
||||
//get the stream data into a single stream variable (databaseStream) regardless whether its preloaded or not:
|
||||
MemoryStream preloadedMemoryStream = _databaseData == null ? null : _databaseData.Result;
|
||||
MemoryStream databaseStream;
|
||||
@@ -167,7 +178,6 @@ namespace keepass2android
|
||||
{
|
||||
Database newDb = _app.LoadDatabase(_ioc, workingCopy, _compositeKey, StatusLogger, _format, _makeCurrent);
|
||||
Kp2aLog.Log("LoadDB OK");
|
||||
|
||||
if (requiresSubsequentSync)
|
||||
{
|
||||
var syncTask = new SynchronizeCachedDatabase(_app, new ActionOnOperationFinished(_app,
|
||||
|
@@ -111,6 +111,45 @@ namespace keepass2android
|
||||
|
||||
protected override View? SnackbarAnchorView => FindViewById(Resource.Id.main_content);
|
||||
|
||||
public class UpdateEntryActivityBroadcastReceiver : BroadcastReceiver
|
||||
{
|
||||
private readonly EntryActivity _activity;
|
||||
|
||||
public UpdateEntryActivityBroadcastReceiver(EntryActivity activity)
|
||||
{
|
||||
_activity = activity;
|
||||
}
|
||||
|
||||
public override void OnReceive(Context? context, Intent? intent)
|
||||
{
|
||||
if (intent?.Action == Intents.DataUpdated)
|
||||
{
|
||||
_activity.OnDataUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDataUpdated()
|
||||
{
|
||||
if (Entry == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var entryUId = Entry.Uuid;
|
||||
if (!App.Kp2a.CurrentDb.EntriesById.ContainsKey(entryUId))
|
||||
{
|
||||
Finish();
|
||||
return;
|
||||
}
|
||||
var newEntry = App.Kp2a.CurrentDb.EntriesById[entryUId];
|
||||
if (!newEntry.EqualsEntry(Entry, PwCompareOptions.None, MemProtCmpMode.Full))
|
||||
{
|
||||
Recreate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void Launch(Activity act, PwEntry pw, int pos, AppTask appTask, ActivityFlags? flags = null, int historyIndex=-1)
|
||||
{
|
||||
Intent i = new Intent(act, typeof(EntryActivity));
|
||||
@@ -502,7 +541,13 @@ namespace keepass2android
|
||||
|
||||
//the rest of the things to do depends on the current app task:
|
||||
AppTask.CompleteOnCreateEntryActivity(this, notifyPluginsOnOpenThread);
|
||||
}
|
||||
|
||||
_dataUpdatedIntentReceiver = new UpdateEntryActivityBroadcastReceiver(this);
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.AddAction(Intents.DataUpdated);
|
||||
ContextCompat.RegisterReceiver(this, _dataUpdatedIntentReceiver, filter, (int)ReceiverFlags.Exported);
|
||||
|
||||
}
|
||||
|
||||
private void RemoveFromHistory()
|
||||
{
|
||||
@@ -1083,7 +1128,9 @@ namespace keepass2android
|
||||
UnregisterReceiver(_pluginActionReceiver);
|
||||
if (_pluginFieldReceiver != null)
|
||||
UnregisterReceiver(_pluginFieldReceiver);
|
||||
base.OnDestroy();
|
||||
if (_dataUpdatedIntentReceiver != null)
|
||||
UnregisterReceiver(_dataUpdatedIntentReceiver);
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
private void NotifyPluginsOnClose()
|
||||
@@ -1359,6 +1406,7 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
bool isPaused = false;
|
||||
private UpdateEntryActivityBroadcastReceiver _dataUpdatedIntentReceiver;
|
||||
|
||||
protected override void OnPause()
|
||||
{
|
||||
|
@@ -533,10 +533,9 @@ namespace keepass2android
|
||||
}
|
||||
});
|
||||
//make sure we can close the EntryEditActivity activity even if the app went to background till we get to the OnOperationFinishedHandler Action
|
||||
closeOrShowError.AllowInactiveActivity = true;
|
||||
|
||||
|
||||
ActionOnOperationFinished afterAddEntry = new ActionOnOperationFinished(App.Kp2a, (success, message, activity) =>
|
||||
|
||||
ActionOnOperationFinished afterAddEntry = new ActionOnOperationFinished(App.Kp2a, (success, message, activity) =>
|
||||
{
|
||||
if (success && activity is EntryEditActivity entryEditActivity)
|
||||
AppTask.AfterAddNewEntry(entryEditActivity, newEntry);
|
||||
|
@@ -45,6 +45,7 @@ using AndroidX.AppCompat.Widget;
|
||||
using Google.Android.Material.Dialog;
|
||||
using keepass2android.views;
|
||||
using SearchView = AndroidX.AppCompat.Widget.SearchView;
|
||||
using AndroidX.Core.Content;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
@@ -275,6 +276,7 @@ namespace keepass2android
|
||||
private IMenuItem searchItem;
|
||||
private IMenuItem searchItemDummy;
|
||||
private bool isPaused;
|
||||
private UpdateGroupBaseActivityBroadcastReceiver _dataUpdatedIntentReceiver;
|
||||
|
||||
protected override void OnResume()
|
||||
{
|
||||
@@ -746,9 +748,10 @@ namespace keepass2android
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_dataUpdatedIntentReceiver = new UpdateGroupBaseActivityBroadcastReceiver(this);
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.AddAction(Intents.DataUpdated);
|
||||
ContextCompat.RegisterReceiver(this, _dataUpdatedIntentReceiver, filter, (int)ReceiverFlags.Exported);
|
||||
|
||||
SetResult(KeePass.ExitNormal);
|
||||
|
||||
@@ -1034,6 +1037,13 @@ namespace keepass2android
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
UnregisterReceiver(_dataUpdatedIntentReceiver);
|
||||
base.OnDestroy();
|
||||
|
||||
}
|
||||
|
||||
public override bool OnCreateOptionsMenu(IMenu menu)
|
||||
{
|
||||
|
||||
@@ -1417,6 +1427,50 @@ namespace keepass2android
|
||||
return FindViewById<BackgroundOperationContainer>(Resource.Id.background_ops_container);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDataUpdated()
|
||||
{
|
||||
if (Group == null || FragmentManager.IsDestroyed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var groupId = Group.Uuid;
|
||||
if (!App.Kp2a.CurrentDb.GroupsById.ContainsKey(groupId))
|
||||
{
|
||||
Finish();
|
||||
return;
|
||||
}
|
||||
Group = App.Kp2a.CurrentDb.GroupsById[groupId];
|
||||
var fragment = FragmentManager.FindFragmentById<GroupListFragment>(Resource.Id.list_fragment);
|
||||
if (fragment == null)
|
||||
{
|
||||
throw new Exception("did not find fragment");
|
||||
}
|
||||
fragment.ListAdapter = new PwGroupListAdapter(this, Group);
|
||||
SetGroupIcon();
|
||||
SetGroupTitle();
|
||||
ListAdapter?.NotifyDataSetChanged();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class UpdateGroupBaseActivityBroadcastReceiver : BroadcastReceiver
|
||||
{
|
||||
private readonly GroupBaseActivity _groupBaseActivity;
|
||||
|
||||
public UpdateGroupBaseActivityBroadcastReceiver(GroupBaseActivity groupBaseActivity)
|
||||
{
|
||||
_groupBaseActivity = groupBaseActivity;
|
||||
}
|
||||
|
||||
public override void OnReceive(Context? context, Intent? intent)
|
||||
{
|
||||
if (intent?.Action == Intents.DataUpdated)
|
||||
{
|
||||
_groupBaseActivity.OnDataUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class GroupListFragment : ListFragment, AbsListView.IMultiChoiceModeListener
|
||||
|
@@ -38,7 +38,7 @@ namespace keepass2android
|
||||
protected const string NoLockCheck = "NO_LOCK_CHECK";
|
||||
|
||||
protected IOConnectionInfo _ioc;
|
||||
private BroadcastReceiver _intentReceiver;
|
||||
private BroadcastReceiver _lockCloseIntentReceiver;
|
||||
private ActivityDesign _design;
|
||||
|
||||
public LockCloseActivity()
|
||||
@@ -66,11 +66,11 @@ namespace keepass2android
|
||||
if (Intent.GetBooleanExtra(NoLockCheck, false))
|
||||
return;
|
||||
|
||||
_intentReceiver = new LockCloseActivityBroadcastReceiver(this);
|
||||
_lockCloseIntentReceiver = new LockCloseActivityBroadcastReceiver(this);
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.AddAction(Intents.DatabaseLocked);
|
||||
filter.AddAction(Intent.ActionScreenOff);
|
||||
ContextCompat.RegisterReceiver(this, _intentReceiver, filter, (int)ReceiverFlags.Exported);
|
||||
ContextCompat.RegisterReceiver(this, _lockCloseIntentReceiver, filter, (int)ReceiverFlags.Exported);
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
@@ -79,7 +79,7 @@ namespace keepass2android
|
||||
{
|
||||
try
|
||||
{
|
||||
UnregisterReceiver(_intentReceiver);
|
||||
UnregisterReceiver(_lockCloseIntentReceiver);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@@ -1444,7 +1444,7 @@ namespace keepass2android
|
||||
LoadDb task = (KeyProviderTypes.Contains(KeyProviders.Otp))
|
||||
? new SaveOtpAuxFileAndLoadDb(App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, GetKeyProviderString(),
|
||||
onOperationFinishedHandler, this, true, _makeCurrent)
|
||||
: new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, GetKeyProviderString(), onOperationFinishedHandler,true, _makeCurrent);
|
||||
: new LoadDb(App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, GetKeyProviderString(), onOperationFinishedHandler,true, _makeCurrent);
|
||||
_loadDbFileTask = null; // prevent accidental re-use
|
||||
|
||||
new BlockingOperationRunner(App.Kp2a, task).Run();
|
||||
@@ -1886,7 +1886,7 @@ namespace keepass2android
|
||||
Handler handler = new Handler();
|
||||
OnOperationFinishedHandler onOperationFinishedHandler = new AfterLoad(handler, this, _ioConnection);
|
||||
_performingLoad = true;
|
||||
LoadDb task = new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKeyForImmediateLoad, GetKeyProviderString(),
|
||||
LoadDb task = new LoadDb(App.Kp2a, _ioConnection, _loadDbFileTask, compositeKeyForImmediateLoad, GetKeyProviderString(),
|
||||
onOperationFinishedHandler, false, _makeCurrent);
|
||||
_loadDbFileTask = null; // prevent accidental re-use
|
||||
new BlockingOperationRunner(App.Kp2a, task).Run();
|
||||
@@ -2276,7 +2276,7 @@ namespace keepass2android
|
||||
private readonly PasswordActivity _act;
|
||||
|
||||
|
||||
public SaveOtpAuxFileAndLoadDb(IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey, string keyfileOrProvider, OnOperationFinishedHandler operationFinishedHandler, PasswordActivity act, bool updateLastUsageTimestamp, bool makeCurrent) : base(act, app, ioc, databaseData, compositeKey, keyfileOrProvider, operationFinishedHandler,updateLastUsageTimestamp,makeCurrent)
|
||||
public SaveOtpAuxFileAndLoadDb(IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey, string keyfileOrProvider, OnOperationFinishedHandler operationFinishedHandler, PasswordActivity act, bool updateLastUsageTimestamp, bool makeCurrent) : base(app, ioc, databaseData, compositeKey, keyfileOrProvider, operationFinishedHandler,updateLastUsageTimestamp,makeCurrent)
|
||||
{
|
||||
_act = act;
|
||||
}
|
||||
|
@@ -151,11 +151,17 @@ namespace keepass2android
|
||||
BroadcastDatabaseAction(LocaleManager.LocalizedAppContext, Strings.ActionCloseDatabase);
|
||||
|
||||
// Couldn't quick-lock, so unload database(s) instead
|
||||
_openAttempts.Clear();
|
||||
_openDatabases.Clear();
|
||||
_currentDatabase = null;
|
||||
LastOpenedEntry = null;
|
||||
QuickLocked = false;
|
||||
|
||||
lock (_openDatabasesLock)
|
||||
{
|
||||
_openAttempts.Clear();
|
||||
_openDatabases.Clear();
|
||||
|
||||
_currentDatabase = null;
|
||||
LastOpenedEntry = null;
|
||||
QuickLocked = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -193,39 +199,59 @@ namespace keepass2android
|
||||
|
||||
public Database LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compositeKey, IKp2aStatusLogger statusLogger, IDatabaseFormat databaseFormat, bool makeCurrent)
|
||||
{
|
||||
var prefs = PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext);
|
||||
var createBackup = prefs.GetBoolean(LocaleManager.LocalizedAppContext.GetString(Resource.String.CreateBackups_key), true)
|
||||
|
||||
|
||||
|
||||
var prefs = PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext);
|
||||
var createBackup =
|
||||
prefs.GetBoolean(LocaleManager.LocalizedAppContext.GetString(Resource.String.CreateBackups_key),
|
||||
true)
|
||||
&& !(new LocalFileStorage(this).IsLocalBackup(ioConnectionInfo));
|
||||
|
||||
MemoryStream backupCopy = new MemoryStream();
|
||||
if (createBackup)
|
||||
{
|
||||
MemoryStream backupCopy = new MemoryStream();
|
||||
if (createBackup)
|
||||
{
|
||||
|
||||
memoryStream.CopyTo(backupCopy);
|
||||
backupCopy.Seek(0, SeekOrigin.Begin);
|
||||
//reset stream if we need to reuse it later:
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
memoryStream.CopyTo(backupCopy);
|
||||
backupCopy.Seek(0, SeekOrigin.Begin);
|
||||
//reset stream if we need to reuse it later:
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
foreach (Database openDb in _openDatabases)
|
||||
{
|
||||
if (openDb.Ioc.IsSameFileAs(ioConnectionInfo))
|
||||
{
|
||||
//TODO check this earlier and simply open the database's root group
|
||||
throw new Exception("Database already loaded!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_openAttempts.Add(ioConnectionInfo);
|
||||
var newDb = new Database(new DrawableFactory(), this);
|
||||
|
||||
_openAttempts.Add(ioConnectionInfo);
|
||||
var newDb = new Database(new DrawableFactory(), this);
|
||||
newDb.LoadData(this, ioConnectionInfo, memoryStream, compositeKey, statusLogger, databaseFormat);
|
||||
|
||||
|
||||
|
||||
if ((_currentDatabase == null) || makeCurrent)
|
||||
_currentDatabase = newDb;
|
||||
_openDatabases.Add(newDb);
|
||||
lock (_openDatabasesLock)
|
||||
{
|
||||
if ((_currentDatabase == null) || makeCurrent) _currentDatabase = newDb;
|
||||
|
||||
bool replacedOpenDatabase = false;
|
||||
for (int i = 0; i < _openDatabases.Count; i++)
|
||||
{
|
||||
if (_openDatabases[i].Ioc.IsSameFileAs(ioConnectionInfo))
|
||||
{
|
||||
if (_currentDatabase == _openDatabases[i])
|
||||
{
|
||||
_currentDatabase = newDb;
|
||||
}
|
||||
|
||||
replacedOpenDatabase = true;
|
||||
_openDatabases[i] = newDb;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!replacedOpenDatabase)
|
||||
{
|
||||
_openDatabases.Add(newDb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -285,21 +311,27 @@ namespace keepass2android
|
||||
|
||||
public void CloseDatabase(Database db)
|
||||
{
|
||||
if (!_openDatabases.Contains(db))
|
||||
throw new Exception("Cannot close database which is not open!");
|
||||
if (_openDatabases.Count == 1)
|
||||
{
|
||||
Lock(false);
|
||||
return;
|
||||
}
|
||||
if (LastOpenedEntry != null && db.EntriesById.ContainsKey(LastOpenedEntry.Uuid))
|
||||
{
|
||||
LastOpenedEntry = null;
|
||||
}
|
||||
|
||||
_openDatabases.Remove(db);
|
||||
if (_currentDatabase == db)
|
||||
_currentDatabase = _openDatabases.First();
|
||||
lock (_openDatabasesLock)
|
||||
{
|
||||
//TODO check that Lock() below works without a deadlock
|
||||
if (!_openDatabases.Contains(db))
|
||||
throw new Exception("Cannot close database which is not open!");
|
||||
if (_openDatabases.Count == 1)
|
||||
{
|
||||
Lock(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LastOpenedEntry != null && db.EntriesById.ContainsKey(LastOpenedEntry.Uuid))
|
||||
{
|
||||
LastOpenedEntry = null;
|
||||
}
|
||||
|
||||
_openDatabases.Remove(db);
|
||||
if (_currentDatabase == db)
|
||||
_currentDatabase = _openDatabases.First();
|
||||
}
|
||||
|
||||
UpdateOngoingNotification();
|
||||
//TODO broadcast event so affected activities can close/update?
|
||||
}
|
||||
@@ -376,12 +408,20 @@ namespace keepass2android
|
||||
|
||||
private readonly List<IOConnectionInfo> _openAttempts = new List<IOConnectionInfo>(); //stores which files have been attempted to open. Used to avoid that we repeatedly try to load files which failed to load.
|
||||
private readonly List<Database> _openDatabases = new List<Database>();
|
||||
private readonly object _openDatabasesLock = new object();
|
||||
private readonly List<IOConnectionInfo> _childDatabases = new List<IOConnectionInfo>(); //list of databases which were opened as child databases
|
||||
private Database _currentDatabase;
|
||||
|
||||
public IEnumerable<Database> OpenDatabases
|
||||
{
|
||||
get { return _openDatabases; }
|
||||
get
|
||||
{
|
||||
lock (_openDatabasesLock)
|
||||
{
|
||||
//avoid concurrent access to _openDatabases
|
||||
return new List<Database>(_openDatabases);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal ChallengeXCKey _currentlyWaitingXcKey;
|
||||
@@ -415,8 +455,9 @@ namespace keepass2android
|
||||
DirtyGroups.Add(group);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
var intent = new Intent(Intents.DataUpdated);
|
||||
App.Context.SendBroadcast(intent);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -1345,13 +1386,22 @@ namespace keepass2android
|
||||
|
||||
public Database TryFindDatabaseForElement(IStructureItem element)
|
||||
{
|
||||
foreach (var db in OpenDatabases)
|
||||
try
|
||||
{
|
||||
//we compare UUIDs and not by reference. this is more robust and works with history items as well
|
||||
if (db.Elements.Any(e => e.Uuid?.Equals(element.Uuid) == true))
|
||||
return db;
|
||||
foreach (var db in OpenDatabases)
|
||||
{
|
||||
//we compare UUIDs and not by reference. this is more robust and works with history items as well
|
||||
if (db.Elements.Any(e => e.Uuid?.Equals(element.Uuid) == true))
|
||||
{
|
||||
return db;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
catch (Exception e)
|
||||
{
|
||||
Kp2aLog.LogUnexpectedError(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void RegisterChildDatabase(IOConnectionInfo ioc)
|
||||
|
@@ -37,8 +37,13 @@ namespace keepass2android
|
||||
/// <summary>This intent will be broadcast once the database has been locked. Sensitive information displayed should be hidden and unloaded.</summary>
|
||||
public const String DatabaseLocked = "keepass2android." + AppNames.PackagePart + ".database_locked";
|
||||
|
||||
/// <summary>This intent will be broadcast once the keyboard data has been cleared</summary>
|
||||
public const String KeyboardCleared = "keepass2android." + AppNames.PackagePart + ".keyboard_cleared";
|
||||
/// <summary>
|
||||
/// Signals that the loaded data was updated, e.g. by reloading during sync. All UI elements should be refreshed.
|
||||
/// </summary>
|
||||
public const String DataUpdated = "keepass2android." + AppNames.PackagePart + ".data_updated";
|
||||
|
||||
/// <summary>This intent will be broadcast once the keyboard data has been cleared</summary>
|
||||
public const String KeyboardCleared = "keepass2android." + AppNames.PackagePart + ".keyboard_cleared";
|
||||
|
||||
public const String CopyUsername = "keepass2android.copy_username";
|
||||
public const String CopyPassword = "keepass2android.copy_password";
|
||||
|
Reference in New Issue
Block a user