first version to have multiple databases open at the same time. needs testing and bug fixing.

This commit is contained in:
Philipp Crocoll
2018-10-16 06:33:00 +02:00
parent 8a993b7dcb
commit a2dab72b25
73 changed files with 1329 additions and 669 deletions

View File

@@ -485,12 +485,6 @@ namespace KeePassLib
set { m_pbHashOfLastIO = value; } set { m_pbHashOfLastIO = value; }
} }
public bool UseFileTransactions
{
get { return m_bUseFileTransactions; }
set { m_bUseFileTransactions = value; }
}
public bool UseFileLocks public bool UseFileLocks
{ {
get { return m_bUseFileLocks; } get { return m_bUseFileLocks; }

View File

@@ -360,5 +360,12 @@ namespace KeePassLib.Serialization
m_ioCredProtMode = IOCredProtMode.None; m_ioCredProtMode = IOCredProtMode.None;
} }
} }
public bool IsSameFileAs(IOConnectionInfo other)
{
if (other == null)
return false;
return Path == other.Path && UserName == other.UserName;
}
} }
} }

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Net.Security; using System.Net.Security;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using Android.App; using Android.App;
@@ -33,26 +34,37 @@ namespace keepass2android
/// This also contains methods which are UI specific and should be replacable for testing. /// This also contains methods which are UI specific and should be replacable for testing.
public interface IKp2aApp : ICertificateValidationHandler public interface IKp2aApp : ICertificateValidationHandler
{ {
/// <summary> /// <summary>
/// Locks the currently open database, quicklocking if available (unless false is passed for allowQuickUnlock) /// Locks all currently open databases, quicklocking if available (unless false is passed for allowQuickUnlock)
/// </summary> /// </summary>
void LockDatabase(bool allowQuickUnlock = true); void Lock(bool allowQuickUnlock);
/// <summary>
/// Loads the specified data as the currently open database, as unlocked.
/// </summary>
void LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compKey,
ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat);
/// <summary> /// <summary>
/// Returns the current database /// Loads the specified data as the currently open database, as unlocked.
/// </summary> /// </summary>
Database GetDb(); Database LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compKey, ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat);
/// <summary>
/// Tell the app that the file from ioc was opened with keyfile. HashSet<PwGroup> DirtyGroups { get; }
/// </summary>
void StoreOpenedFileAsRecent(IOConnectionInfo ioc, string keyfile, string displayName = ""); void MarkAllGroupsAsDirty();
/// <summary>
/// Returns the current database
/// </summary>
Database CurrentDb { get; }
IEnumerable<Database> OpenDatabases { get; }
void CloseDatabase(Database db);
Database FindDatabaseForGroupId(PwUuid groupKey);
Database FindDatabaseForEntryId(PwUuid entryId);
/// <summary>
/// Tell the app that the file from ioc was opened with keyfile.
/// </summary>
void StoreOpenedFileAsRecent(IOConnectionInfo ioc, string keyfile, string displayName = "");
/// <summary> /// <summary>
/// Creates a new database and returns it /// Creates a new database and returns it
@@ -111,6 +123,10 @@ namespace keepass2android
bool CheckForDuplicateUuids { get; } bool CheckForDuplicateUuids { get; }
#if !NoNet #if !NoNet
ICertificateErrorHandler CertificateErrorHandler { get; } ICertificateErrorHandler CertificateErrorHandler { get; }
#endif #endif
}
}
} }

View File

@@ -90,8 +90,9 @@
<ItemGroup> <ItemGroup>
<Compile Include="database\CheckDatabaseForChanges.cs" /> <Compile Include="database\CheckDatabaseForChanges.cs" />
<Compile Include="database\edit\AddTemplateEntries.cs" /> <Compile Include="database\edit\AddTemplateEntries.cs" />
<Compile Include="database\edit\ChangeTemplateIds.cs" />
<Compile Include="database\edit\CopyEntry.cs" /> <Compile Include="database\edit\CopyEntry.cs" />
<Compile Include="database\edit\DeleteMultipleItems.cs" /> <Compile Include="database\edit\DeleteMultipleItemsFromOneDatabase.cs" />
<Compile Include="database\edit\EditGroup.cs" /> <Compile Include="database\edit\EditGroup.cs" />
<Compile Include="database\edit\MoveElements.cs" /> <Compile Include="database\edit\MoveElements.cs" />
<Compile Include="database\KdbDatabaseFormat.cs" /> <Compile Include="database\KdbDatabaseFormat.cs" />

View File

@@ -23,7 +23,7 @@ namespace keepass2android
/// <summary> /// <summary>
/// EqualityComparer implementation to compare PwGroups based on their Id /// EqualityComparer implementation to compare PwGroups based on their Id
/// </summary> /// </summary>
class PwGroupEqualityFromIdComparer: IEqualityComparer<PwGroup> public class PwGroupEqualityFromIdComparer: IEqualityComparer<PwGroup>
{ {
#region IEqualityComparer implementation #region IEqualityComparer implementation
public bool Equals (PwGroup x, PwGroup y) public bool Equals (PwGroup x, PwGroup y)

View File

@@ -86,6 +86,11 @@ namespace keepass2android
ReadOnlyReason_PreKitKat, ReadOnlyReason_PreKitKat,
ReadOnlyReason_ReadOnlyFlag, ReadOnlyReason_ReadOnlyFlag,
ReadOnlyReason_ReadOnlyKitKat, ReadOnlyReason_ReadOnlyKitKat,
ReadOnlyReason_LocalBackup ReadOnlyReason_LocalBackup,
UpdatingTemplateIds,
ChangleLegacyTemplateIds_Message,
ChangleLegacyTemplateIds_Title,
Ok,
cancel
} }
} }

View File

@@ -29,7 +29,7 @@ namespace keepass2android
{ {
try try
{ {
IOConnectionInfo ioc = _app.GetDb().Ioc; IOConnectionInfo ioc = _app.CurrentDb.Ioc;
IFileStorage fileStorage = _app.GetFileStorage(ioc); IFileStorage fileStorage = _app.GetFileStorage(ioc);
if (fileStorage is CachingFileStorage) if (fileStorage is CachingFileStorage)
{ {
@@ -49,7 +49,7 @@ namespace keepass2android
hashingRemoteStream.CopyTo(remoteData); hashingRemoteStream.CopyTo(remoteData);
hashingRemoteStream.Close(); hashingRemoteStream.Close();
if (!MemUtil.ArraysEqual(_app.GetDb().KpDatabase.HashOfFileOnDisk, hashingRemoteStream.Hash)) if (!MemUtil.ArraysEqual(_app.CurrentDb.KpDatabase.HashOfFileOnDisk, hashingRemoteStream.Hash))
{ {
_app.TriggerReload(_context); _app.TriggerReload(_context);
Finish(true); Finish(true);

View File

@@ -38,7 +38,6 @@ namespace keepass2android
public Dictionary<PwUuid, PwGroup> Groups = new Dictionary<PwUuid, PwGroup>(new PwUuidEqualityComparer()); public Dictionary<PwUuid, PwGroup> Groups = new Dictionary<PwUuid, PwGroup>(new PwUuidEqualityComparer());
public Dictionary<PwUuid, PwEntry> Entries = new Dictionary<PwUuid, PwEntry>(new PwUuidEqualityComparer()); public Dictionary<PwUuid, PwEntry> Entries = new Dictionary<PwUuid, PwEntry>(new PwUuidEqualityComparer());
public HashSet<PwGroup> Dirty = new HashSet<PwGroup>(new PwGroupEqualityFromIdComparer());
public PwGroup Root; public PwGroup Root;
public PwDatabase KpDatabase; public PwDatabase KpDatabase;
public IOConnectionInfo Ioc public IOConnectionInfo Ioc
@@ -49,11 +48,6 @@ namespace keepass2android
} }
} }
/// <summary>
/// Information about the last opened entry. Includes the entry but also transformed fields.
/// </summary>
public PwEntryOutput LastOpenedEntry { get; set; }
/// <summary> /// <summary>
/// if an OTP key was used, this property tells the location of the OTP auxiliary file. /// if an OTP key was used, this property tells the location of the OTP auxiliary file.
/// Must be set after loading. /// Must be set after loading.
@@ -74,16 +68,11 @@ namespace keepass2android
CanWrite = true; //default CanWrite = true; //default
} }
private bool _reloadRequested; private IDatabaseFormat _databaseFormat = new KdbxDatabaseFormat(KdbxFormat.Default);
private IDatabaseFormat _databaseFormat = new KdbxDatabaseFormat(KdbxFormat.Default);
public bool ReloadRequested public bool ReloadRequested { get; set; }
{
get { return _reloadRequested; }
set { _reloadRequested = value; }
}
public bool DidOpenFileChange() public bool DidOpenFileChange()
{ {
return _app.GetFileStorage(Ioc).CheckForFileChangeFast(Ioc, LastFileVersion); return _app.GetFileStorage(Ioc).CheckForFileChangeFast(Ioc, LastFileVersion);
} }
@@ -195,8 +184,7 @@ namespace keepass2android
public void SaveData() { public void SaveData() {
KpDatabase.UseFileTransactions = _app.GetBooleanPreference(PreferenceKey.UseFileTransactions); using (IWriteTransaction trans = _app.GetFileStorage(Ioc).OpenWriteTransaction(Ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions)))
using (IWriteTransaction trans = _app.GetFileStorage(Ioc).OpenWriteTransaction(Ioc, KpDatabase.UseFileTransactions))
{ {
DatabaseFormat.Save(KpDatabase, trans.OpenFile()); DatabaseFormat.Save(KpDatabase, trans.OpenFile());
@@ -243,14 +231,6 @@ namespace keepass2android
PopulateGlobals(currentGroup, _app.CheckForDuplicateUuids); PopulateGlobals(currentGroup, _app.CheckForDuplicateUuids);
} }
public void MarkAllGroupsAsDirty() {
foreach ( PwGroup group in Groups.Values ) {
Dirty.Add(group);
}
}
} }

View File

@@ -14,13 +14,13 @@ namespace keepass2android
public class PwEntryOutput public class PwEntryOutput
{ {
private readonly PwEntry _entry; private readonly PwEntry _entry;
private readonly PwDatabase _db; private readonly Database _db;
private readonly ProtectedStringDictionary _outputStrings = new ProtectedStringDictionary(); private readonly ProtectedStringDictionary _outputStrings = new ProtectedStringDictionary();
/// <summary> /// <summary>
/// Constructs the PwEntryOutput by replacing the placeholders /// Constructs the PwEntryOutput by replacing the placeholders
/// </summary> /// </summary>
public PwEntryOutput(PwEntry entry, PwDatabase db) public PwEntryOutput(PwEntry entry, Database db)
{ {
_entry = entry; _entry = entry;
_db = db; _db = db;
@@ -34,7 +34,7 @@ namespace keepass2android
string GetStringAndReplacePlaceholders(string key) string GetStringAndReplacePlaceholders(string key)
{ {
String value = Entry.Strings.ReadSafe(key); String value = Entry.Strings.ReadSafe(key);
value = SprEngine.Compile(value, new SprContext(Entry, _db, SprCompileFlags.All)); value = SprEngine.Compile(value, new SprContext(Entry, _db.KpDatabase, SprCompileFlags.All));
return value; return value;
} }

View File

@@ -26,7 +26,7 @@ namespace keepass2android
{ {
try try
{ {
IOConnectionInfo ioc = _app.GetDb().Ioc; IOConnectionInfo ioc = _app.CurrentDb.Ioc;
IFileStorage fileStorage = _app.GetFileStorage(ioc); IFileStorage fileStorage = _app.GetFileStorage(ioc);
if (!(fileStorage is CachingFileStorage)) if (!(fileStorage is CachingFileStorage))
{ {
@@ -70,10 +70,10 @@ namespace keepass2android
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully)); Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
} }
_saveDb = null; _saveDb = null;
}), false, remoteData); }), _app.CurrentDb, false, remoteData);
_saveDb.Run(); _saveDb.Run();
_app.GetDb().MarkAllGroupsAsDirty(); _app.MarkAllGroupsAsDirty();
} }
else else
{ {

View File

@@ -24,7 +24,7 @@ namespace keepass2android
public class AddEntry : RunnableOnFinish { public class AddEntry : RunnableOnFinish {
protected Database Db protected Database Db
{ {
get { return _app.GetDb(); } get { return _app.CurrentDb; }
} }
private readonly IKp2aApp _app; private readonly IKp2aApp _app;
@@ -43,7 +43,7 @@ namespace keepass2android
_app = app; _app = app;
_entry = entry; _entry = entry;
_onFinishToRun = new AfterAdd(ctx, app.GetDb(), entry, OnFinishToRun); _onFinishToRun = new AfterAdd(ctx, app.CurrentDb, entry, app,OnFinishToRun);
} }
@@ -60,7 +60,7 @@ namespace keepass2android
// Commit to disk // Commit to disk
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun); SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
save.SetStatusLogger(StatusLogger); save.SetStatusLogger(StatusLogger);
save.Run(); save.Run();
} }
@@ -68,12 +68,13 @@ namespace keepass2android
private class AfterAdd : OnFinish { private class AfterAdd : OnFinish {
private readonly Database _db; private readonly Database _db;
private readonly PwEntry _entry; private readonly PwEntry _entry;
private readonly IKp2aApp _app;
public AfterAdd(Activity activity, Database db, PwEntry entry, OnFinish finish):base(activity, finish) { public AfterAdd(Activity activity, Database db, PwEntry entry, IKp2aApp app, OnFinish finish):base(activity, finish) {
_db = db; _db = db;
_entry = entry; _entry = entry;
_app = app;
} }
@@ -83,7 +84,7 @@ namespace keepass2android
PwGroup parent = _entry.ParentGroup; PwGroup parent = _entry.ParentGroup;
// Mark parent group dirty // Mark parent group dirty
_db.Dirty.Add(parent); _app.DirtyGroups.Add(parent);
// Add entry to global // Add entry to global
_db.Entries[_entry.Uuid] = _entry; _db.Entries[_entry.Uuid] = _entry;

View File

@@ -26,9 +26,12 @@ namespace keepass2android
public class AddGroup : RunnableOnFinish { public class AddGroup : RunnableOnFinish {
internal Database Db internal Database Db
{ {
get { return _app.GetDb(); } get { return _app.CurrentDb; }
} }
private IKp2aApp _app;
public IKp2aApp App { get => _app; }
private IKp2aApp _app;
private readonly String _name; private readonly String _name;
private readonly int _iconId; private readonly int _iconId;
private readonly PwUuid _groupCustomIconId; private readonly PwUuid _groupCustomIconId;
@@ -69,7 +72,7 @@ namespace keepass2android
Parent.AddGroup(Group, true); Parent.AddGroup(Group, true);
// Commit to disk // Commit to disk
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, DontSave); SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun, DontSave);
save.SetStatusLogger(StatusLogger); save.SetStatusLogger(StatusLogger);
save.Run(); save.Run();
} }
@@ -86,7 +89,7 @@ namespace keepass2android
if ( Success ) { if ( Success ) {
// Mark parent group dirty // Mark parent group dirty
_addGroup.Db.Dirty.Add(_addGroup.Parent); _addGroup.App.DirtyGroups.Add(_addGroup.Parent);
// Add group to global list // Add group to global list
_addGroup.Db.Groups[_addGroup.Group.Uuid] = _addGroup.Group; _addGroup.Db.Groups[_addGroup.Group.Uuid] = _addGroup.Group;

View File

@@ -28,7 +28,7 @@ namespace keepass2android
{ {
public class AddTemplateEntries : RunnableOnFinish { public class AddTemplateEntries : RunnableOnFinish {
class TemplateEntry public class TemplateEntry
{ {
public UiStringKey Title { get; set; } public UiStringKey Title { get; set; }
public PwIcon Icon { get; set; } public PwIcon Icon { get; set; }
@@ -47,11 +47,12 @@ namespace keepass2android
void AddToEntry(IKp2aApp app, PwEntry entry, int position); void AddToEntry(IKp2aApp app, PwEntry entry, int position);
} }
internal enum FieldType public enum FieldType
{ {
Inline, ProtectedInline Inline, ProtectedInline
} }
internal enum SpecialFieldKey
public enum SpecialFieldKey
{ {
ExpDate, OverrideUrl, Tags ExpDate, OverrideUrl, Tags
} }
@@ -125,7 +126,7 @@ namespace keepass2android
protected Database Db protected Database Db
{ {
get { return _app.GetDb(); } get { return _app.CurrentDb; }
} }
private readonly IKp2aApp _app; private readonly IKp2aApp _app;
@@ -140,7 +141,7 @@ namespace keepass2android
//_onFinishToRun = new AfterAdd(this, OnFinishToRun); //_onFinishToRun = new AfterAdd(this, OnFinishToRun);
} }
static readonly List<TemplateEntry> TemplateEntries = new List<TemplateEntry>() public static readonly List<TemplateEntry> TemplateEntries = new List<TemplateEntry>()
{ {
new TemplateEntry() new TemplateEntry()
{ {
@@ -285,12 +286,23 @@ namespace keepass2android
}; };
public static bool ContainsAllTemplates(IKp2aApp app) public static bool ContainsAllTemplates(Database db)
{ {
return TemplateEntries.All(t => app.GetDb().Entries.ContainsKey(t.Uuid)); return TemplateEntries.All(t =>
{
string hexId = t.Uuid.ToHexString();
return db.Entries.Any(kvp => kvp.Key.Equals(t.Uuid) ||
kvp.Value.Strings.ReadSafe(TemplateIdStringKey) == hexId);
});
} }
public override void Run() { public static string TemplateIdStringKey
{
get { return "KP2A_TemplateId"; }
}
public override void Run() {
StatusLogger.UpdateMessage(UiStringKey.AddingEntry); StatusLogger.UpdateMessage(UiStringKey.AddingEntry);
List<PwEntry> addedEntries; List<PwEntry> addedEntries;
@@ -298,10 +310,10 @@ namespace keepass2android
if (addedEntries.Any()) if (addedEntries.Any())
{ {
_app.GetDb().Dirty.Add(templateGroup); _app.DirtyGroups.Add(templateGroup);
// Commit to disk // Commit to disk
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun); SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
save.SetStatusLogger(StatusLogger); save.SetStatusLogger(StatusLogger);
save.Run(); save.Run();
} }
@@ -315,37 +327,38 @@ namespace keepass2android
} }
PwGroup templateGroup; PwGroup templateGroup;
if (!_app.GetDb().Groups.TryGetValue(_app.GetDb().KpDatabase.EntryTemplatesGroup, out templateGroup)) if (!_app.CurrentDb.Groups.TryGetValue(_app.CurrentDb.KpDatabase.EntryTemplatesGroup, out templateGroup))
{ {
//create template group //create template group
templateGroup = new PwGroup(true, true, _app.GetResourceString(UiStringKey.TemplateGroupName), PwIcon.Folder); templateGroup = new PwGroup(true, true, _app.GetResourceString(UiStringKey.TemplateGroupName), PwIcon.Folder);
_app.GetDb().KpDatabase.RootGroup.AddGroup(templateGroup, true); _app.CurrentDb.KpDatabase.RootGroup.AddGroup(templateGroup, true);
_app.GetDb().KpDatabase.EntryTemplatesGroup = templateGroup.Uuid; _app.CurrentDb.KpDatabase.EntryTemplatesGroup = templateGroup.Uuid;
_app.GetDb().KpDatabase.EntryTemplatesGroupChanged = DateTime.Now; _app.CurrentDb.KpDatabase.EntryTemplatesGroupChanged = DateTime.Now;
_app.GetDb().Dirty.Add(_app.GetDb().KpDatabase.RootGroup); _app.DirtyGroups.Add(_app.CurrentDb.KpDatabase.RootGroup);
_app.GetDb().Groups[templateGroup.Uuid] = templateGroup; _app.CurrentDb.Groups[templateGroup.Uuid] = templateGroup;
} }
addedEntries = new List<PwEntry>(); addedEntries = new List<PwEntry>();
foreach (var template in TemplateEntries) foreach (var template in TemplateEntries)
{ {
if (_app.GetDb().Entries.ContainsKey(template.Uuid)) if (_app.CurrentDb.Entries.ContainsKey(template.Uuid))
continue; continue;
PwEntry entry = CreateEntry(template); PwEntry entry = CreateEntry(template);
templateGroup.AddEntry(entry, true); templateGroup.AddEntry(entry, true);
addedEntries.Add(entry); addedEntries.Add(entry);
_app.GetDb().Entries[entry.Uuid] = entry; _app.CurrentDb.Entries[entry.Uuid] = entry;
} }
return templateGroup; return templateGroup;
} }
private PwEntry CreateEntry(TemplateEntry template) private PwEntry CreateEntry(TemplateEntry template)
{ {
PwEntry entry = new PwEntry(false, true); PwEntry entry = new PwEntry(true, true);
entry.Uuid = template.Uuid;
entry.IconId = template.Icon; entry.IconId = template.Icon;
entry.Strings.Set(PwDefs.TitleField, new ProtectedString(false, _app.GetResourceString(template.Title))); entry.Strings.Set(PwDefs.TitleField, new ProtectedString(false, _app.GetResourceString(template.Title)));
entry.Strings.Set("_etm_template", new ProtectedString(false, "1")); entry.Strings.Set("_etm_template", new ProtectedString(false, "1"));
entry.Strings.Set(TemplateIdStringKey, new ProtectedString(false, template.Uuid.ToHexString()));
int position = 0; int position = 0;
foreach (var field in template.Fields) foreach (var field in template.Fields)
{ {
@@ -375,6 +388,10 @@ namespace keepass2android
} }
public static bool IsTemplateId(PwUuid pwUuid)
{
return TemplateEntries.Any(te => te.Uuid.Equals(pwUuid));
}
} }
} }

View File

@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using KeePassLib;
using KeePassLib.Security;
namespace keepass2android.database.edit
{
public class ChangeTemplateIds: RunnableOnFinish
{
private readonly IKp2aApp _app;
private readonly Database _db;
private string _etmTemplateUuid { get { return "_etm_template_uuid"; } }
public static string TemplateIdStringKey
{
get { return "KP2A_TemplateId"; }
}
public ChangeTemplateIds(Activity activeActivity, IKp2aApp app, Database db, OnFinish finish) : base(activeActivity, finish)
{
_app = app;
_db = db;
}
public override void Run()
{
StatusLogger.UpdateMessage(UiStringKey.UpdatingTemplateIds);
Dictionary<string, string> uuidMap = new Dictionary<string, string>();
foreach (var templateEntry in AddTemplateEntries.TemplateEntries)
{
PwEntry entry;
if (_db.Entries.TryGetValue(templateEntry.Uuid, out entry))
{
PwUuid oldUuid = entry.Uuid;
entry.Uuid = new PwUuid(true);
uuidMap[oldUuid.ToHexString()] = entry.Uuid.ToHexString();
entry.Strings.Set(TemplateIdStringKey,new ProtectedString(false, oldUuid.ToHexString()));
_db.Entries.Remove(oldUuid);
_db.Entries[entry.Uuid] = entry;
}
}
foreach (var entry in _db.Entries.Values)
{
string templateUuid = entry.Strings.ReadSafe(_etmTemplateUuid);
if (templateUuid != null)
{
string newTemplateUuid;
if (uuidMap.TryGetValue(templateUuid, out newTemplateUuid))
{
entry.Strings.Set(_etmTemplateUuid, new ProtectedString(false, newTemplateUuid));
}
}
}
if (uuidMap.Any())
{
SaveDb save = new SaveDb( ActiveActivity, _app, _db, OnFinishToRun);
save.SetStatusLogger(StatusLogger);
save.Run();
}
else
{
OnFinishToRun?.Run();
}
}
}
}

View File

@@ -84,7 +84,7 @@ namespace keepass2android
addTemplates.AddTemplates(out addedEntries); addTemplates.AddTemplates(out addedEntries);
// Commit changes // Commit changes
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, _dontSave); SaveDb save = new SaveDb(_ctx, _app, db, OnFinishToRun, _dontSave);
save.SetStatusLogger(StatusLogger); save.SetStatusLogger(StatusLogger);
_onFinishToRun = null; _onFinishToRun = null;
save.Run(); save.Run();

View File

@@ -31,7 +31,7 @@ namespace keepass2android
public DeleteEntry(Activity activiy, IKp2aApp app, PwEntry entry, OnFinish finish):base(activiy, finish, app) { public DeleteEntry(Activity activiy, IKp2aApp app, PwEntry entry, OnFinish finish):base(activiy, finish, app) {
Ctx = activiy; Ctx = activiy;
Db = app.GetDb(); Db = app.FindDatabaseForEntryId(entry.Uuid);
_entry = entry; _entry = entry;
} }
@@ -40,7 +40,7 @@ namespace keepass2android
{ {
get get
{ {
return App.GetDb().DatabaseFormat.CanRecycle && CanRecycleGroup(_entry.ParentGroup); return Db.DatabaseFormat.CanRecycle && CanRecycleGroup(_entry.ParentGroup);
} }
} }

View File

@@ -47,7 +47,7 @@ namespace keepass2android
*/ */
private void SetMembers(Activity activity, IKp2aApp app, PwGroup group, bool dontSave) private void SetMembers(Activity activity, IKp2aApp app, PwGroup group, bool dontSave)
{ {
base.SetMembers(activity, app.GetDb()); base.SetMembers(activity, app.FindDatabaseForGroupId(group.Uuid));
_group = group; _group = group;
DontSave = dontSave; DontSave = dontSave;
@@ -58,7 +58,7 @@ namespace keepass2android
{ {
get get
{ {
return App.GetDb().DatabaseFormat.CanRecycle && CanRecycleGroup(_group); return Db.DatabaseFormat.CanRecycle && CanRecycleGroup(_group);
} }
} }

View File

@@ -7,12 +7,12 @@ using KeePassLib.Interfaces;
namespace keepass2android namespace keepass2android
{ {
public class DeleteMultipleItems : DeleteRunnable public class DeleteMultipleItemsFromOneDatabase : DeleteRunnable
{ {
private readonly List<IStructureItem> _elementsToDelete; private readonly List<IStructureItem> _elementsToDelete;
private readonly bool _canRecycle; private readonly bool _canRecycle;
public DeleteMultipleItems(Activity activity, Database db, List<IStructureItem> elementsToDelete, OnFinish finish, IKp2aApp app) public DeleteMultipleItemsFromOneDatabase(Activity activity, Database db, List<IStructureItem> elementsToDelete, OnFinish finish, IKp2aApp app)
: base(activity, finish, app) : base(activity, finish, app)
{ {
_elementsToDelete = elementsToDelete; _elementsToDelete = elementsToDelete;
@@ -26,7 +26,7 @@ namespace keepass2android
private bool DetermineCanRecycle() private bool DetermineCanRecycle()
{ {
Android.Util.Log.Debug("KP2A", "CanRecycle?"); Android.Util.Log.Debug("KP2A", "CanRecycle?");
if (!App.GetDb().DatabaseFormat.CanRecycle) if (!Db.DatabaseFormat.CanRecycle)
{ {
Android.Util.Log.Debug("KP2A", "CanRecycle? No because of DB format."); Android.Util.Log.Debug("KP2A", "CanRecycle? No because of DB format.");
return false; return false;

View File

@@ -130,6 +130,7 @@ namespace keepass2android
DeletePermanently = true; DeletePermanently = true;
ProgressTask pt = new ProgressTask(App, Ctx, this); ProgressTask pt = new ProgressTask(App, Ctx, this);
pt.Run(); pt.Run();
}, },
(dlgSender, dlgEvt) => (dlgSender, dlgEvt) =>
{ {
@@ -215,11 +216,11 @@ namespace keepass2android
if (success) if (success)
{ {
foreach (var g in touchedGroups) foreach (var g in touchedGroups)
Db.Dirty.Add(g); App.DirtyGroups.Add(g);
foreach (var g in permanentlyDeletedGroups) foreach (var g in permanentlyDeletedGroups)
{ {
//remove groups from global lists if present there //remove groups from global lists if present there
Db.Dirty.Remove(g); App.DirtyGroups.Remove(g);
Db.Groups.Remove(g.Uuid); Db.Groups.Remove(g.Uuid);
} }
@@ -227,12 +228,12 @@ namespace keepass2android
else else
{ {
// Let's not bother recovering from a failure to save. It is too much work. // Let's not bother recovering from a failure to save. It is too much work.
App.LockDatabase(false); App.Lock(false);
} }
}, OnFinishToRun); }, OnFinishToRun);
// Commit database // Commit database
SaveDb save = new SaveDb(Ctx, App, OnFinishToRun, false); SaveDb save = new SaveDb(Ctx, App, Db, OnFinishToRun, false);
save.SetStatusLogger(StatusLogger); save.SetStatusLogger(StatusLogger);
save.Run(); save.Run();

View File

@@ -26,9 +26,12 @@ namespace keepass2android
public class EditGroup : RunnableOnFinish { public class EditGroup : RunnableOnFinish {
internal Database Db internal Database Db
{ {
get { return _app.GetDb(); } get { return _app.FindDatabaseForGroupId(Group.Uuid); }
} }
private IKp2aApp _app;
public IKp2aApp App { get => _app; }
private IKp2aApp _app;
private readonly String _name; private readonly String _name;
private readonly PwIcon _iconId; private readonly PwIcon _iconId;
private readonly PwUuid _customIconId; private readonly PwUuid _customIconId;
@@ -57,7 +60,7 @@ namespace keepass2android
Group.Touch(true); Group.Touch(true);
// Commit to disk // Commit to disk
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun); SaveDb save = new SaveDb(_ctx, _app, Db, OnFinishToRun);
save.SetStatusLogger(StatusLogger); save.SetStatusLogger(StatusLogger);
save.Run(); save.Run();
} }
@@ -76,10 +79,10 @@ namespace keepass2android
if ( Success ) { if ( Success ) {
// Mark parent group dirty // Mark parent group dirty
_editGroup.Db.Dirty.Add(_editGroup.Group.ParentGroup); _editGroup.App.DirtyGroups.Add(_editGroup.Group.ParentGroup);
} else } else
{ {
_editGroup._app.LockDatabase(false); _editGroup._app.Lock(false);
} }
base.Run(); base.Run();

View File

@@ -21,6 +21,7 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Android.App; using Android.App;
using keepass2android.database.edit;
using KeePassLib; using KeePassLib;
using KeePassLib.Keys; using KeePassLib.Keys;
using KeePassLib.Serialization; using KeePassLib.Serialization;
@@ -48,6 +49,7 @@ namespace keepass2android
_rememberKeyfile = app.GetBooleanPreference(PreferenceKey.remember_keyfile); _rememberKeyfile = app.GetBooleanPreference(PreferenceKey.remember_keyfile);
} }
protected bool success = false;
public override void Run() public override void Run()
{ {
@@ -78,6 +80,10 @@ namespace keepass2android
//ok, try to load the database. Let's start with Kdbx format and retry later if that is the wrong guess: //ok, try to load the database. Let's start with Kdbx format and retry later if that is the wrong guess:
_format = new KdbxDatabaseFormat(KdbpFile.GetFormatToUse(_ioc)); _format = new KdbxDatabaseFormat(KdbpFile.GetFormatToUse(_ioc));
TryLoad(databaseStream); TryLoad(databaseStream);
success = true;
} }
catch (Exception e) catch (Exception e)
{ {
@@ -125,7 +131,7 @@ namespace keepass2android
/// </summary> /// </summary>
public Exception Exception { get; set; } public Exception Exception { get; set; }
private void TryLoad(MemoryStream databaseStream) Database TryLoad(MemoryStream databaseStream)
{ {
//create a copy of the stream so we can try again if we get an exception which indicates we should change parameters //create a copy of the stream so we can try again if we get an exception which indicates we should change parameters
//This is not optimal in terms of (short-time) memory usage but is hard to avoid because the Keepass library closes streams also in case of errors. //This is not optimal in terms of (short-time) memory usage but is hard to avoid because the Keepass library closes streams also in case of errors.
@@ -138,19 +144,89 @@ namespace keepass2android
//now let's go: //now let's go:
try try
{ {
_app.LoadDatabase(_ioc, workingCopy, _compositeKey, StatusLogger, _format); Database newDb = _app.LoadDatabase(_ioc, workingCopy, _compositeKey, StatusLogger, _format);
Kp2aLog.Log("LoadDB OK"); Kp2aLog.Log("LoadDB OK");
//make sure the stored access time for the actual file is more recent than that of its backup //make sure the stored access time for the actual file is more recent than that of its backup
Thread.Sleep(10); Thread.Sleep(10);
SaveFileData(_ioc, _keyfileOrProvider); SaveFileData(_ioc, _keyfileOrProvider);
Finish(true, _format.SuccessMessage);
bool hasLegacyTemplateIds = false;
//make sure we never have entries with same Uuids
foreach (var entryKey in newDb.Entries.Keys)
{
foreach (Database otherDb in _app.OpenDatabases)
{
if (otherDb == newDb)
continue;
if (otherDb.Entries.ContainsKey(entryKey))
{
if (AddTemplateEntries.IsTemplateId(entryKey))
{
hasLegacyTemplateIds = true;
}
else
{
_app.CloseDatabase(newDb);
throw new Exception("Database contains entry id " + entryKey.ToHexString() + "(" +
newDb.Entries[entryKey].Strings.ReadSafe(PwDefs.TitleField)
+ ") which is already contained in " +
_app.GetFileStorage(otherDb.Ioc).GetDisplayName(otherDb.Ioc) +
"! Please close the other database before opening this one.");
}
}
}
}
foreach (var groupKey in newDb.Groups.Keys)
{
foreach (Database otherDb in _app.OpenDatabases)
{
if (otherDb == newDb)
continue;
if (otherDb.Groups.ContainsKey(groupKey))
{
throw new Exception("Database contains group id " + groupKey.ToHexString() + "(" +
newDb.Groups[groupKey].Name + ") which is already contained in " +
_app.GetFileStorage(otherDb.Ioc).GetDisplayName(otherDb.Ioc) +
"! Please close the other database before opening this one.");
}
}
}
if (hasLegacyTemplateIds)
{
_app.AskYesNoCancel(UiStringKey.ChangleLegacyTemplateIds_Title, UiStringKey.ChangleLegacyTemplateIds_Message,UiStringKey.Ok, UiStringKey.cancel,
/*yes*/
(sender, args) =>
{
ChangeTemplateIds cti = new ChangeTemplateIds(ActiveActivity, _app, newDb, new ActionOnFinish(ActiveActivity, (b, message, activity) => Finish(b, message)));
cti.Run();
},
/*no*/
(sender, args) =>
{
_app.CloseDatabase(newDb);
Finish(false);
},
null,
ActiveActivity
);
}
else
Finish(true, _format.SuccessMessage);
return newDb;
} }
catch (OldFormatException) catch (OldFormatException)
{ {
_format = new KdbDatabaseFormat(_app); _format = new KdbDatabaseFormat(_app);
TryLoad(databaseStream); return TryLoad(databaseStream);
} }
catch (InvalidCompositeKeyException) catch (InvalidCompositeKeyException)
{ {
@@ -162,7 +238,7 @@ namespace keepass2android
//retry without password: //retry without password:
_compositeKey.RemoveUserKey(passwordKey); _compositeKey.RemoveUserKey(passwordKey);
//retry: //retry:
TryLoad(databaseStream); return TryLoad(databaseStream);
} }
else throw; else throw;
} }

View File

@@ -53,8 +53,8 @@ namespace keepass2android.database.edit
foreach (var elementToMove in _elementsToMove) foreach (var elementToMove in _elementsToMove)
{ {
_app.GetDb().Dirty.Add(elementToMove.ParentGroup); _app.DirtyGroups.Add(elementToMove.ParentGroup);
//TODO is this safe when transferring between databases?
PwGroup pgParent = elementToMove.ParentGroup; PwGroup pgParent = elementToMove.ParentGroup;
if (pgParent != _targetGroup) if (pgParent != _targetGroup)
{ {
@@ -87,12 +87,15 @@ namespace keepass2android.database.edit
{ {
if (!success) if (!success)
{ // Let's not bother recovering from a failure. { // Let's not bother recovering from a failure.
_app.LockDatabase(false); _app.Lock(false);
} }
}, OnFinishToRun); }, OnFinishToRun);
//Unchecked
//TODO save the right database
// Save // Save
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, false); SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun, false);
save.SetStatusLogger(StatusLogger); save.SetStatusLogger(StatusLogger);
save.Run(); save.Run();
} }

View File

@@ -34,7 +34,8 @@ namespace keepass2android
public class SaveDb : RunnableOnFinish { public class SaveDb : RunnableOnFinish {
private readonly IKp2aApp _app; private readonly IKp2aApp _app;
private readonly bool _dontSave; private readonly Database _db;
private readonly bool _dontSave;
/// <summary> /// <summary>
/// stream for reading the data from the original file. If this is set to a non-null value, we know we need to sync /// stream for reading the data from the original file. If this is set to a non-null value, we know we need to sync
@@ -43,9 +44,10 @@ namespace keepass2android
private readonly Context _ctx; private readonly Context _ctx;
private Thread _workerThread; private Thread _workerThread;
public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish, bool dontSave) public SaveDb(Activity ctx, IKp2aApp app, Database db, OnFinish finish, bool dontSave)
: base(ctx, finish) : base(ctx, finish)
{ {
_db = db;
_ctx = ctx; _ctx = ctx;
_app = app; _app = app;
_dontSave = dontSave; _dontSave = dontSave;
@@ -59,21 +61,23 @@ namespace keepass2android
/// <param name="finish"></param> /// <param name="finish"></param>
/// <param name="dontSave"></param> /// <param name="dontSave"></param>
/// <param name="streamForOrigFile">Stream for reading the data from the (changed) original location</param> /// <param name="streamForOrigFile">Stream for reading the data from the (changed) original location</param>
public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish, bool dontSave, Stream streamForOrigFile) public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish, Database db, bool dontSave, Stream streamForOrigFile)
: base(ctx, finish) : base(ctx, finish)
{ {
_db = db;
_ctx = ctx; _ctx = ctx;
_app = app; _app = app;
_dontSave = dontSave; _dontSave = dontSave;
_streamForOrigFile = streamForOrigFile; _streamForOrigFile = streamForOrigFile;
} }
public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish) public SaveDb(Activity ctx, IKp2aApp app, Database db, OnFinish finish)
: base(ctx, finish) : base(ctx, finish)
{ {
_ctx = ctx; _ctx = ctx;
_app = app; _app = app;
_dontSave = false; _db = db;
_dontSave = false;
} }
@@ -84,7 +88,7 @@ namespace keepass2android
{ {
try try
{ {
if (_app.GetDb().CanWrite == false) if (_db.CanWrite == false)
{ {
//this should only happen if there is a problem in the UI so that the user sees an edit interface. //this should only happen if there is a problem in the UI so that the user sees an edit interface.
Finish(false,"Cannot save changes. File is read-only!"); Finish(false,"Cannot save changes. File is read-only!");
@@ -92,13 +96,13 @@ namespace keepass2android
} }
StatusLogger.UpdateMessage(UiStringKey.saving_database); StatusLogger.UpdateMessage(UiStringKey.saving_database);
IOConnectionInfo ioc = _app.GetDb().Ioc; IOConnectionInfo ioc = _db.Ioc;
IFileStorage fileStorage = _app.GetFileStorage(ioc); IFileStorage fileStorage = _app.GetFileStorage(ioc);
if (_streamForOrigFile == null) if (_streamForOrigFile == null)
{ {
if ((!_app.GetBooleanPreference(PreferenceKey.CheckForFileChangesOnSave)) if ((!_app.GetBooleanPreference(PreferenceKey.CheckForFileChangesOnSave))
|| (_app.GetDb().KpDatabase.HashOfFileOnDisk == null)) //first time saving || (_db.KpDatabase.HashOfFileOnDisk == null)) //first time saving
{ {
PerformSaveWithoutCheck(fileStorage, ioc); PerformSaveWithoutCheck(fileStorage, ioc);
Finish(true); Finish(true);
@@ -109,8 +113,8 @@ namespace keepass2android
if ( if (
(_streamForOrigFile != null) (_streamForOrigFile != null)
|| fileStorage.CheckForFileChangeFast(ioc, _app.GetDb().LastFileVersion) //first try to use the fast change detection || fileStorage.CheckForFileChangeFast(ioc, _db.LastFileVersion) //first try to use the fast change detection
|| (FileHashChanged(ioc, _app.GetDb().KpDatabase.HashOfFileOnDisk) == FileHashChange.Changed) //if that fails, hash the file and compare: || (FileHashChanged(ioc, _db.KpDatabase.HashOfFileOnDisk) == FileHashChange.Changed) //if that fails, hash the file and compare:
) )
{ {
@@ -217,13 +221,13 @@ namespace keepass2android
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.SynchronizingDatabase)); StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.SynchronizingDatabase));
PwDatabase pwImp = new PwDatabase(); PwDatabase pwImp = new PwDatabase();
PwDatabase pwDatabase = _app.GetDb().KpDatabase; PwDatabase pwDatabase = _db.KpDatabase;
pwImp.New(new IOConnectionInfo(), pwDatabase.MasterKey); pwImp.New(new IOConnectionInfo(), pwDatabase.MasterKey);
pwImp.MemoryProtection = pwDatabase.MemoryProtection.CloneDeep(); pwImp.MemoryProtection = pwDatabase.MemoryProtection.CloneDeep();
pwImp.MasterKey = pwDatabase.MasterKey; pwImp.MasterKey = pwDatabase.MasterKey;
var stream = GetStreamForBaseFile(fileStorage, ioc); var stream = GetStreamForBaseFile(fileStorage, ioc);
_app.GetDb().DatabaseFormat.PopulateDatabaseFromStream(pwImp, stream, null); _db.DatabaseFormat.PopulateDatabaseFromStream(pwImp, stream, null);
pwDatabase.MergeIn(pwImp, PwMergeMethod.Synchronize, null); pwDatabase.MergeIn(pwImp, PwMergeMethod.Synchronize, null);
@@ -249,8 +253,8 @@ namespace keepass2android
private void PerformSaveWithoutCheck(IFileStorage fileStorage, IOConnectionInfo ioc) private void PerformSaveWithoutCheck(IFileStorage fileStorage, IOConnectionInfo ioc)
{ {
StatusLogger.UpdateSubMessage(""); StatusLogger.UpdateSubMessage("");
_app.GetDb().SaveData(); _db.SaveData();
_app.GetDb().LastFileVersion = fileStorage.GetCurrentFileVersionFast(ioc); _db.LastFileVersion = fileStorage.GetCurrentFileVersionFast(ioc);
} }
public byte[] HashOriginalFile(IOConnectionInfo iocFile) public byte[] HashOriginalFile(IOConnectionInfo iocFile)

View File

@@ -52,7 +52,7 @@ namespace keepass2android
public override void Run () public override void Run ()
{ {
StatusLogger.UpdateMessage(UiStringKey.SettingPassword); StatusLogger.UpdateMessage(UiStringKey.SettingPassword);
PwDatabase pm = _app.GetDb().KpDatabase; PwDatabase pm = _app.CurrentDb.KpDatabase;
CompositeKey newKey = new CompositeKey (); CompositeKey newKey = new CompositeKey ();
if (String.IsNullOrEmpty (_password) == false) { if (String.IsNullOrEmpty (_password) == false) {
newKey.AddUserKey (new KcpPassword (_password)); newKey.AddUserKey (new KcpPassword (_password));
@@ -74,7 +74,7 @@ namespace keepass2android
// Save Database // Save Database
_onFinishToRun = new AfterSave(ActiveActivity, previousKey, previousMasterKeyChanged, pm, OnFinishToRun); _onFinishToRun = new AfterSave(ActiveActivity, previousKey, previousMasterKeyChanged, pm, OnFinishToRun);
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, _dontSave); SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun, _dontSave);
save.SetStatusLogger(StatusLogger); save.SetStatusLogger(StatusLogger);
save.Run(); save.Run();
} }

View File

@@ -36,7 +36,7 @@ namespace keepass2android
public override void Run() { public override void Run() {
// Commit to disk // Commit to disk
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun); SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
save.SetStatusLogger(StatusLogger); save.SetStatusLogger(StatusLogger);
save.Run(); save.Run();
} }
@@ -59,7 +59,7 @@ namespace keepass2android
if ( parent != null ) { if ( parent != null ) {
// Mark parent group dirty // Mark parent group dirty
_app.GetDb().Dirty.Add(parent); _app.DirtyGroups.Add(parent);
} }

View File

@@ -26,7 +26,7 @@ namespace keepass2android
b.SetMessage(Resource.String.killed_by_os); b.SetMessage(Resource.String.killed_by_os);
b.SetPositiveButton(Android.Resource.String.Ok, delegate b.SetPositiveButton(Android.Resource.String.Ok, delegate
{ {
Intent i = new Intent(this, typeof(FileSelectActivity)); Intent i = new Intent(this, typeof(SelectCurrentDbActivity));
i.AddFlags(ActivityFlags.ClearTask | ActivityFlags.NewTask); i.AddFlags(ActivityFlags.ClearTask | ActivityFlags.NewTask);
StartActivity(i); StartActivity(i);

View File

@@ -91,7 +91,7 @@ namespace keepass2android
public class EntryActivity : LockCloseActivity public class EntryActivity : LockCloseActivity
{ {
public const String KeyEntry = "entry"; public const String KeyEntry = "entry";
public const String KeyRefreshPos = "refresh_pos"; public const String KeyRefreshPos = "refresh_pos";
public const String KeyCloseAfterCreate = "close_after_create"; public const String KeyCloseAfterCreate = "close_after_create";
public const String KeyGroupFullPath = "groupfullpath_key"; public const String KeyGroupFullPath = "groupfullpath_key";
@@ -107,6 +107,11 @@ namespace keepass2android
i.PutExtra(KeyEntry, pw.Uuid.ToHexString()); i.PutExtra(KeyEntry, pw.Uuid.ToHexString());
i.PutExtra(KeyRefreshPos, pos); i.PutExtra(KeyRefreshPos, pos);
if (!App.Kp2a.CurrentDb.Entries.ContainsKey(pw.Uuid))
{
App.Kp2a.CurrentDb = App.Kp2a.FindDatabaseForEntryId(pw.Uuid);
}
if (flags != null) if (flags != null)
i.SetFlags((ActivityFlags) flags); i.SetFlags((ActivityFlags) flags);
@@ -167,7 +172,7 @@ namespace keepass2android
protected void SetupEditButtons() { protected void SetupEditButtons() {
View edit = FindViewById(Resource.Id.entry_edit); View edit = FindViewById(Resource.Id.entry_edit);
if (App.Kp2a.GetDb().CanWrite) if (App.Kp2a.CurrentDb.CanWrite)
{ {
edit.Visibility = ViewStates.Visible; edit.Visibility = ViewStates.Visible;
edit.Click += (sender, e) => edit.Click += (sender, e) =>
@@ -265,9 +270,9 @@ namespace keepass2android
//update the Entry output in the App database and notify the CopyToClipboard service //update the Entry output in the App database and notify the CopyToClipboard service
if (App.Kp2a.GetDb()?.LastOpenedEntry != null) if (App.Kp2a.LastOpenedEntry != null)
{ {
App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.Set(key, new ProtectedString(isProtected, value)); App.Kp2a.LastOpenedEntry.OutputStrings.Set(key, new ProtectedString(isProtected, value));
Intent updateKeyboardIntent = new Intent(this, typeof(CopyToClipboardService)); Intent updateKeyboardIntent = new Intent(this, typeof(CopyToClipboardService));
updateKeyboardIntent.SetAction(Intents.UpdateKeyboard); updateKeyboardIntent.SetAction(Intents.UpdateKeyboard);
updateKeyboardIntent.PutExtra(KeyEntry, Entry.Uuid.ToHexString()); updateKeyboardIntent.PutExtra(KeyEntry, Entry.Uuid.ToHexString());
@@ -323,7 +328,7 @@ namespace keepass2android
i.SetPackage(pluginPackage); i.SetPackage(pluginPackage);
i.PutExtra(Strings.ExtraActionData, bundleExtra); i.PutExtra(Strings.ExtraActionData, bundleExtra);
i.PutExtra(Strings.ExtraSender, PackageName); i.PutExtra(Strings.ExtraSender, PackageName);
PluginHost.AddEntryToIntent(i, App.Kp2a.GetDb().LastOpenedEntry); PluginHost.AddEntryToIntent(i, App.Kp2a.LastOpenedEntry);
var menuOption = new PluginMenuOption() var menuOption = new PluginMenuOption()
{ {
@@ -389,7 +394,7 @@ namespace keepass2android
SetEntryView(); SetEntryView();
Database db = App.Kp2a.GetDb(); Database db = App.Kp2a.CurrentDb;
// Likely the app has been killed exit the activity // Likely the app has been killed exit the activity
if (db == null || (App.Kp2a.QuickLocked)) if (db == null || (App.Kp2a.QuickLocked))
{ {
@@ -428,7 +433,7 @@ namespace keepass2android
SetupEditButtons(); SetupEditButtons();
App.Kp2a.GetDb().LastOpenedEntry = new PwEntryOutput(Entry, App.Kp2a.GetDb().KpDatabase); App.Kp2a.LastOpenedEntry = new PwEntryOutput(Entry, App.Kp2a.CurrentDb);
_pluginActionReceiver = new PluginActionReceiver(this); _pluginActionReceiver = new PluginActionReceiver(this);
RegisterReceiver(_pluginActionReceiver, new IntentFilter(Strings.ActionAddEntryAction)); RegisterReceiver(_pluginActionReceiver, new IntentFilter(Strings.ActionAddEntryAction));
@@ -508,8 +513,8 @@ namespace keepass2android
ViewGroup extraGroup = (ViewGroup) FindViewById(Resource.Id.extra_strings); ViewGroup extraGroup = (ViewGroup) FindViewById(Resource.Id.extra_strings);
bool hasExtras = false; bool hasExtras = false;
IEditMode editMode = new DefaultEdit(); IEditMode editMode = new DefaultEdit();
if (KpEntryTemplatedEdit.IsTemplated(App.Kp2a.GetDb(), this.Entry)) if (KpEntryTemplatedEdit.IsTemplated(App.Kp2a.CurrentDb, this.Entry))
editMode = new KpEntryTemplatedEdit(App.Kp2a.GetDb(), this.Entry); editMode = new KpEntryTemplatedEdit(App.Kp2a.CurrentDb, this.Entry);
foreach (var key in editMode.SortExtraFieldKeys(Entry.Strings.GetKeys().Where(key=> !PwDefs.IsStandardField(key)))) foreach (var key in editMode.SortExtraFieldKeys(Entry.Strings.GetKeys().Where(key=> !PwDefs.IsStandardField(key))))
{ {
if (editMode.IsVisible(key)) if (editMode.IsVisible(key))
@@ -936,7 +941,7 @@ namespace keepass2android
private void PopulateStandardText(List<int> viewIds, int containerViewId, String key) private void PopulateStandardText(List<int> viewIds, int containerViewId, String key)
{ {
String value = Entry.Strings.ReadSafe(key); String value = Entry.Strings.ReadSafe(key);
value = SprEngine.Compile(value, new SprContext(Entry, App.Kp2a.GetDb().KpDatabase, SprCompileFlags.All)); value = SprEngine.Compile(value, new SprContext(Entry, App.Kp2a.CurrentDb.KpDatabase, SprCompileFlags.All));
PopulateText(viewIds, containerViewId, value); PopulateText(viewIds, containerViewId, value);
_stringViews.Add(key, new StandardStringView(viewIds, containerViewId, this)); _stringViews.Add(key, new StandardStringView(viewIds, containerViewId, this));
} }
@@ -1012,7 +1017,7 @@ namespace keepass2android
{ {
((IOfflineSwitchable)fileStorage).IsOffline = false; ((IOfflineSwitchable)fileStorage).IsOffline = false;
} }
using (var writeTransaction = fileStorage.OpenWriteTransaction(_targetIoc, _app.GetDb().KpDatabase.UseFileTransactions)) using (var writeTransaction = fileStorage.OpenWriteTransaction(_targetIoc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions)))
{ {
Stream sOut = writeTransaction.OpenFile(); Stream sOut = writeTransaction.OpenFile();
@@ -1173,7 +1178,7 @@ namespace keepass2android
return true; return true;
case Resource.Id.menu_lock: case Resource.Id.menu_lock:
App.Kp2a.LockDatabase(); App.Kp2a.Lock();
return true; return true;
case Android.Resource.Id.Home: case Android.Resource.Id.Home:
//Currently the action bar only displays the home button when we come from a previous activity. //Currently the action bar only displays the home button when we come from a previous activity.
@@ -1264,7 +1269,7 @@ namespace keepass2android
public void AddEntryToIntent(Intent intent) public void AddEntryToIntent(Intent intent)
{ {
PluginHost.AddEntryToIntent(intent, App.Kp2a.GetDb().LastOpenedEntry); PluginHost.AddEntryToIntent(intent, App.Kp2a.LastOpenedEntry);
} }
public void CloseAfterTaskComplete() public void CloseAfterTaskComplete()

View File

@@ -120,7 +120,7 @@ namespace keepass2android
} else } else
{ {
Database db = App.Kp2a.GetDb(); Database db = App.Kp2a.CurrentDb;
App.Kp2a.EntryEditActivityState = new EntryEditActivityState(); App.Kp2a.EntryEditActivityState = new EntryEditActivityState();
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this); ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
@@ -199,7 +199,7 @@ namespace keepass2android
if (State.SelectedIcon) if (State.SelectedIcon)
{ {
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iconButton, this, App.Kp2a.GetDb().KpDatabase, (PwIcon)State.SelectedIconId, State.SelectedCustomIconId, false); App.Kp2a.CurrentDb.DrawableFactory.AssignDrawableTo(iconButton, this, App.Kp2a.CurrentDb.KpDatabase, (PwIcon)State.SelectedIconId, State.SelectedCustomIconId, false);
} }
iconButton.Click += (sender, evt) => { iconButton.Click += (sender, evt) => {
UpdateEntryFromUi(State.Entry); UpdateEntryFromUi(State.Entry);
@@ -371,7 +371,7 @@ namespace keepass2android
private void SetAddExtraStringEnabled() private void SetAddExtraStringEnabled()
{ {
if (!App.Kp2a.GetDb().DatabaseFormat.CanHaveCustomFields) if (!App.Kp2a.CurrentDb.DatabaseFormat.CanHaveCustomFields)
((Button)FindViewById(Resource.Id.add_advanced)).Visibility = ViewStates.Gone; ((Button)FindViewById(Resource.Id.add_advanced)).Visibility = ViewStates.Gone;
} }
@@ -393,7 +393,7 @@ namespace keepass2android
void SaveEntry() void SaveEntry()
{ {
Database db = App.Kp2a.GetDb(); Database db = App.Kp2a.CurrentDb;
EntryEditActivity act = this; EntryEditActivity act = this;
if (!ValidateBeforeSaving()) if (!ValidateBeforeSaving())
@@ -498,7 +498,7 @@ namespace keepass2android
void UpdateEntryFromUi(PwEntry entry) void UpdateEntryFromUi(PwEntry entry)
{ {
Database db = App.Kp2a.GetDb(); Database db = App.Kp2a.CurrentDb;
EntryEditActivity act = this; EntryEditActivity act = this;
entry.Strings.Set(PwDefs.TitleField, new ProtectedString(db.KpDatabase.MemoryProtection.ProtectTitle, entry.Strings.Set(PwDefs.TitleField, new ProtectedString(db.KpDatabase.MemoryProtection.ProtectTitle,
@@ -753,7 +753,7 @@ namespace keepass2android
String generatedPassword = data.GetStringExtra("keepass2android.password.generated_password"); String generatedPassword = data.GetStringExtra("keepass2android.password.generated_password");
byte[] password = StrUtil.Utf8.GetBytes(generatedPassword); byte[] password = StrUtil.Utf8.GetBytes(generatedPassword);
State.Entry.Strings.Set(PwDefs.PasswordField, new ProtectedString(App.Kp2a.GetDb().KpDatabase.MemoryProtection.ProtectPassword, State.Entry.Strings.Set(PwDefs.PasswordField, new ProtectedString(App.Kp2a.CurrentDb.KpDatabase.MemoryProtection.ProtectPassword,
password)); password));
MemUtil.ZeroByteArray(password); MemUtil.ZeroByteArray(password);
@@ -792,7 +792,7 @@ namespace keepass2android
{ {
String key = pair.Key; String key = pair.Key;
String label = key; String label = key;
if ((String.IsNullOrEmpty(label) || (!App.Kp2a.GetDb().DatabaseFormat.SupportsAttachmentKeys))) if ((String.IsNullOrEmpty(label) || (!App.Kp2a.CurrentDb.DatabaseFormat.SupportsAttachmentKeys)))
{ {
label = "<attachment>"; label = "<attachment>";
} }
@@ -820,7 +820,7 @@ namespace keepass2android
addBinaryButton.Enabled = true; addBinaryButton.Enabled = true;
if (!App.Kp2a.GetDb().DatabaseFormat.CanHaveMultipleAttachments) if (!App.Kp2a.CurrentDb.DatabaseFormat.CanHaveMultipleAttachments)
addBinaryButton.Enabled = !State.Entry.Binaries.Any(); addBinaryButton.Enabled = !State.Entry.Binaries.Any();
addBinaryButton.Click += (sender, e) => addBinaryButton.Click += (sender, e) =>
{ {
@@ -921,7 +921,7 @@ namespace keepass2android
{ {
if (_additionalKeys == null) if (_additionalKeys == null)
{ {
_additionalKeys = App.Kp2a.GetDb().Entries _additionalKeys = App.Kp2a.CurrentDb.Entries
.Select(kvp => kvp.Value) .Select(kvp => kvp.Value)
.SelectMany(x => x.Strings.GetKeys().Where(k => !PwDefs.IsStandardField(k))) .SelectMany(x => x.Strings.GetKeys().Where(k => !PwDefs.IsStandardField(k)))
.Where(k => (k != null) && !k.StartsWith("_etm_") ) .Where(k => (k != null) && !k.StartsWith("_etm_") )
@@ -999,7 +999,7 @@ namespace keepass2android
{ {
_editModeHiddenViews = new List<View>(); _editModeHiddenViews = new List<View>();
ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button); ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button);
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(currIconButton, this, App.Kp2a.GetDb().KpDatabase, State.Entry.IconId, State.Entry.CustomIconUuid, false); App.Kp2a.CurrentDb.DrawableFactory.AssignDrawableTo(currIconButton, this, App.Kp2a.CurrentDb.KpDatabase, State.Entry.IconId, State.Entry.CustomIconUuid, false);
PopulateText(Resource.Id.entry_title, State.Entry.Strings.ReadSafe (PwDefs.TitleField)); PopulateText(Resource.Id.entry_title, State.Entry.Strings.ReadSafe (PwDefs.TitleField));
PopulateText(Resource.Id.entry_user_name, State.Entry.Strings.ReadSafe (PwDefs.UserNameField)); PopulateText(Resource.Id.entry_user_name, State.Entry.Strings.ReadSafe (PwDefs.UserNameField));
@@ -1028,7 +1028,7 @@ namespace keepass2android
PopulateBinaries(); PopulateBinaries();
if (App.Kp2a.GetDb().DatabaseFormat.SupportsOverrideUrl) if (App.Kp2a.CurrentDb.DatabaseFormat.SupportsOverrideUrl)
{ {
PopulateText(Resource.Id.entry_override_url, State.Entry.OverrideUrl); PopulateText(Resource.Id.entry_override_url, State.Entry.OverrideUrl);
} }
@@ -1037,7 +1037,7 @@ namespace keepass2android
FindViewById(Resource.Id.entry_override_url_container).Visibility = ViewStates.Gone; FindViewById(Resource.Id.entry_override_url_container).Visibility = ViewStates.Gone;
} }
if (App.Kp2a.GetDb().DatabaseFormat.SupportsTags) if (App.Kp2a.CurrentDb.DatabaseFormat.SupportsTags)
{ {
PopulateText(Resource.Id.entry_tags, StrUtil.TagsToString(State.Entry.Tags, true)); PopulateText(Resource.Id.entry_tags, StrUtil.TagsToString(State.Entry.Tags, true));
} }

View File

@@ -107,7 +107,7 @@ namespace keepass2android
public override void Run() public override void Run()
{ {
StatusLogger.UpdateMessage(UiStringKey.exporting_database); StatusLogger.UpdateMessage(UiStringKey.exporting_database);
var pd = _app.GetDb().KpDatabase; var pd = _app.CurrentDb.KpDatabase;
PwExportInfo pwInfo = new PwExportInfo(pd.RootGroup, pd, true); PwExportInfo pwInfo = new PwExportInfo(pd.RootGroup, pd, true);
try try
@@ -117,7 +117,7 @@ namespace keepass2android
{ {
((IOfflineSwitchable) fileStorage).IsOffline = false; ((IOfflineSwitchable) fileStorage).IsOffline = false;
} }
using (var writeTransaction = fileStorage.OpenWriteTransaction(_targetIoc, _app.GetDb().KpDatabase.UseFileTransactions)) using (var writeTransaction = fileStorage.OpenWriteTransaction(_targetIoc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions)))
{ {
Stream sOut = writeTransaction.OpenFile(); Stream sOut = writeTransaction.OpenFile();
_fileFormat.Export(pwInfo, sOut, new NullStatusLogger()); _fileFormat.Export(pwInfo, sOut, new NullStatusLogger());

View File

@@ -64,7 +64,7 @@ namespace keepass2android
SetContentView(Resource.Layout.fingerprint_setup); SetContentView(Resource.Layout.fingerprint_setup);
Enum.TryParse( Enum.TryParse(
PreferenceManager.GetDefaultSharedPreferences(this).GetString(App.Kp2a.GetDb().CurrentFingerprintModePrefKey, ""), PreferenceManager.GetDefaultSharedPreferences(this).GetString(App.Kp2a.CurrentDb.CurrentFingerprintModePrefKey, ""),
out _unlockMode); out _unlockMode);
_fpIcon = FindViewById<ImageView>(Resource.Id.fingerprint_icon); _fpIcon = FindViewById<ImageView>(Resource.Id.fingerprint_icon);
@@ -174,7 +174,7 @@ namespace keepass2android
string CurrentPreferenceKey string CurrentPreferenceKey
{ {
get { return App.Kp2a.GetDb().CurrentFingerprintPrefKey; } get { return App.Kp2a.CurrentDb.CurrentFingerprintPrefKey; }
} }
private void StoreUnlockMode() private void StoreUnlockMode()
@@ -188,13 +188,13 @@ namespace keepass2android
{ {
if (_unlockMode == FingerprintUnlockMode.FullUnlock) if (_unlockMode == FingerprintUnlockMode.FullUnlock)
{ {
var userKey = App.Kp2a.GetDb().KpDatabase.MasterKey.GetUserKey<KcpPassword>(); var userKey = App.Kp2a.CurrentDb.KpDatabase.MasterKey.GetUserKey<KcpPassword>();
_enc.StoreEncrypted(userKey != null ? userKey.Password.ReadString() : "", CurrentPreferenceKey, edit); _enc.StoreEncrypted(userKey != null ? userKey.Password.ReadString() : "", CurrentPreferenceKey, edit);
} }
else else
_enc.StoreEncrypted("QuickUnlock" /*some dummy data*/, CurrentPreferenceKey, edit); _enc.StoreEncrypted("QuickUnlock" /*some dummy data*/, CurrentPreferenceKey, edit);
} }
edit.PutString(App.Kp2a.GetDb().CurrentFingerprintModePrefKey, _unlockMode.ToString()); edit.PutString(App.Kp2a.CurrentDb.CurrentFingerprintModePrefKey, _unlockMode.ToString());
edit.Commit(); edit.Commit();
} }
@@ -261,7 +261,7 @@ namespace keepass2android
UpdateKeyboardCheckboxVisibility(); UpdateKeyboardCheckboxVisibility();
ISharedPreferencesEditor edit = PreferenceManager.GetDefaultSharedPreferences(this).Edit(); ISharedPreferencesEditor edit = PreferenceManager.GetDefaultSharedPreferences(this).Edit();
edit.PutString(App.Kp2a.GetDb().CurrentFingerprintModePrefKey, _unlockMode.ToString()); edit.PutString(App.Kp2a.CurrentDb.CurrentFingerprintModePrefKey, _unlockMode.ToString());
edit.Commit(); edit.Commit();
return; return;
} }

View File

@@ -69,15 +69,6 @@ namespace keepass2android
public static void Launch (Activity act, PwGroup g, AppTask appTask) public static void Launch (Activity act, PwGroup g, AppTask appTask)
{ {
// Need to use PwDatabase since group may be null
PwDatabase db = App.Kp2a.GetDb().KpDatabase;
if (db == null) {
// Reached if db is null
Log.Debug (Tag, "Tried to launch with null db");
return;
}
Intent i = new Intent(act, typeof(GroupActivity)); Intent i = new Intent(act, typeof(GroupActivity));
if ( g != null ) { if ( g != null ) {
@@ -105,10 +96,15 @@ namespace keepass2android
protected override bool AddEntryEnabled protected override bool AddEntryEnabled
{ {
get { return App.Kp2a.GetDb().CanWrite && ((this.Group.ParentGroup != null) || App.Kp2a.GetDb().DatabaseFormat.CanHaveEntriesInRootGroup); } get { return App.Kp2a.CurrentDb.CanWrite && ((this.Group.ParentGroup != null) || App.Kp2a.CurrentDb.DatabaseFormat.CanHaveEntriesInRootGroup); }
} }
private class TemplateListAdapter : ArrayAdapter<PwEntry> protected override bool AddGroupEnabled
{
get { return App.Kp2a.CurrentDb.CanWrite; }
}
private class TemplateListAdapter : ArrayAdapter<PwEntry>
{ {
public TemplateListAdapter(IntPtr handle, JniHandleOwnership transfer) : base(handle, transfer) public TemplateListAdapter(IntPtr handle, JniHandleOwnership transfer) : base(handle, transfer)
{ {
@@ -149,8 +145,7 @@ namespace keepass2android
int size = (int)(Util.convertDpToPixel(Util.convertDpToPixel(20, Context), Context)); int size = (int)(Util.convertDpToPixel(Util.convertDpToPixel(20, Context), Context));
var bmp = var bmp =
Bitmap.CreateScaledBitmap( Bitmap.CreateScaledBitmap(
Util.DrawableToBitmap(App.Kp2a.GetDb() Util.DrawableToBitmap(App.Kp2a.CurrentDb .DrawableFactory.GetIconDrawable(Context, App.Kp2a.CurrentDb.KpDatabase, templateEntry.IconId, PwUuid.Zero, false)),
.DrawableFactory.GetIconDrawable(Context, App.Kp2a.GetDb().KpDatabase, templateEntry.IconId, PwUuid.Zero, false)),
size, size, size, size,
true); true);
@@ -193,7 +188,7 @@ namespace keepass2android
PwUuid id = RetrieveGroupId (intent); PwUuid id = RetrieveGroupId (intent);
Database db = App.Kp2a.GetDb(); Database db = App.Kp2a.CurrentDb;
if (id == null) { if (id == null) {
Group = db.Root; Group = db.Root;
} else { } else {
@@ -221,8 +216,8 @@ namespace keepass2android
View addEntry = FindViewById (Resource.Id.fabAddNewEntry); View addEntry = FindViewById (Resource.Id.fabAddNewEntry);
addEntry.Click += (sender, e) => addEntry.Click += (sender, e) =>
{ {
if (App.Kp2a.GetDb().DatabaseFormat.SupportsTemplates && if (App.Kp2a.CurrentDb.DatabaseFormat.SupportsTemplates &&
!AddTemplateEntries.ContainsAllTemplates(App.Kp2a) && !AddTemplateEntries.ContainsAllTemplates(App.Kp2a.CurrentDb) &&
PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(Askaddtemplates, true)) PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(Askaddtemplates, true))
{ {
App.Kp2a.AskYesNoCancel(UiStringKey.AskAddTemplatesTitle, UiStringKey.AskAddTemplatesMessage,UiStringKey.yes, UiStringKey.no, App.Kp2a.AskYesNoCancel(UiStringKey.AskAddTemplatesTitle, UiStringKey.AskAddTemplatesMessage,UiStringKey.yes, UiStringKey.no,
@@ -256,14 +251,14 @@ namespace keepass2android
FragmentManager.FindFragmentById<GroupListFragment>(Resource.Id.list_fragment).ListAdapter = new PwGroupListAdapter(this, Group); FragmentManager.FindFragmentById<GroupListFragment>(Resource.Id.list_fragment).ListAdapter = new PwGroupListAdapter(this, Group);
Log.Warn(Tag, "Finished creating group"); Log.Warn(Tag, "Finished creating group");
var ioc = App.Kp2a.GetDb().Ioc; var ioc = App.Kp2a.CurrentDb.Ioc;
OptionalOut<UiStringKey> reason = new OptionalOut<UiStringKey>(); OptionalOut<UiStringKey> reason = new OptionalOut<UiStringKey>();
if (App.Kp2a.GetFileStorage(ioc).IsReadOnly(ioc, reason)) if (App.Kp2a.GetFileStorage(ioc).IsReadOnly(ioc, reason))
{ {
bool hasShownReadOnlyReason = bool hasShownReadOnlyReason =
PreferenceManager.GetDefaultSharedPreferences(this) PreferenceManager.GetDefaultSharedPreferences(this)
.GetBoolean(App.Kp2a.GetDb().IocAsHexString() + "_readonlyreason", false); .GetBoolean(App.Kp2a.CurrentDb.IocAsHexString() + "_readonlyreason", false);
if (!hasShownReadOnlyReason) if (!hasShownReadOnlyReason)
{ {
var b = new AlertDialog.Builder(this); var b = new AlertDialog.Builder(this);
@@ -273,7 +268,7 @@ namespace keepass2android
(sender, args) => (sender, args) =>
{ {
PreferenceManager.GetDefaultSharedPreferences(this). PreferenceManager.GetDefaultSharedPreferences(this).
Edit().PutBoolean(App.Kp2a.GetDb().IocAsHexString() + "_readonlyreason", true).Commit(); Edit().PutBoolean(App.Kp2a.CurrentDb.IocAsHexString() + "_readonlyreason", true).Commit();
}); });
b.Show(); b.Show();
} }
@@ -287,11 +282,11 @@ namespace keepass2android
defaultTemplate.IconId = PwIcon.Key; defaultTemplate.IconId = PwIcon.Key;
defaultTemplate.Strings.Set(PwDefs.TitleField, new ProtectedString(false, GetString(Resource.String.DefaultTemplate))); defaultTemplate.Strings.Set(PwDefs.TitleField, new ProtectedString(false, GetString(Resource.String.DefaultTemplate)));
List<PwEntry> templates = new List<PwEntry>() {defaultTemplate}; List<PwEntry> templates = new List<PwEntry>() {defaultTemplate};
if ((!PwUuid.Zero.Equals(App.Kp2a.GetDb().KpDatabase.EntryTemplatesGroup)) if ((!PwUuid.Zero.Equals(App.Kp2a.CurrentDb.KpDatabase.EntryTemplatesGroup))
&& (App.Kp2a.GetDb().KpDatabase.RootGroup.FindGroup(App.Kp2a.GetDb().KpDatabase.EntryTemplatesGroup, true) != null)) && (App.Kp2a.CurrentDb.KpDatabase.RootGroup.FindGroup(App.Kp2a.CurrentDb.KpDatabase.EntryTemplatesGroup, true) != null))
{ {
templates.AddRange( templates.AddRange(
App.Kp2a.GetDb().Groups[App.Kp2a.GetDb().KpDatabase.EntryTemplatesGroup].Entries.OrderBy( App.Kp2a.CurrentDb.Groups[App.Kp2a.CurrentDb.KpDatabase.EntryTemplatesGroup].Entries.OrderBy(
entr => entr.Strings.ReadSafe(PwDefs.TitleField))); entr => entr.Strings.ReadSafe(PwDefs.TitleField)));
} }
if (templates.Count > 1) if (templates.Count > 1)
@@ -316,7 +311,12 @@ namespace keepass2android
cv.OnCreateMenu(menu, menuInfo); cv.OnCreateMenu(menu, menuInfo);
} }
public override void OnBackPressed() public override bool EntriesBelongToCurrentDatabaseOnly
{
get { return true; }
}
public override void OnBackPressed()
{ {
base.OnBackPressed(); base.OnBackPressed();
//if ((Group != null) && (Group.ParentGroup != null)) //if ((Group != null) && (Group.ParentGroup != null))

View File

@@ -95,11 +95,11 @@ namespace keepass2android
protected virtual bool AddGroupEnabled protected virtual bool AddGroupEnabled
{ {
get { return App.Kp2a.GetDb().CanWrite; } get { return false; }
} }
protected virtual bool AddEntryEnabled protected virtual bool AddEntryEnabled
{ {
get { return App.Kp2a.GetDb().CanWrite; } get { return false; }
} }
public void SetNormalButtonVisibility(bool showAddGroup, bool showAddEntry) public void SetNormalButtonVisibility(bool showAddGroup, bool showAddEntry)
@@ -186,7 +186,7 @@ namespace keepass2android
else else
{ {
PwUuid groupUuid = new PwUuid(MemUtil.HexStringToByteArray(strGroupUuid)); PwUuid groupUuid = new PwUuid(MemUtil.HexStringToByteArray(strGroupUuid));
task = new EditGroup(this, App.Kp2a, groupName, (PwIcon)groupIconId, groupCustomIconId, App.Kp2a.GetDb().Groups[groupUuid], task = new EditGroup(this, App.Kp2a, groupName, (PwIcon)groupIconId, groupCustomIconId, App.Kp2a.FindGroup(groupUuid),
new RefreshTask(handler, this)); new RefreshTask(handler, this));
} }
ProgressTask pt = new ProgressTask(App.Kp2a, act, task); ProgressTask pt = new ProgressTask(App.Kp2a, act, task);
@@ -258,7 +258,7 @@ namespace keepass2android
{ {
FingerprintUnlockMode um; FingerprintUnlockMode um;
Enum.TryParse(_prefs.GetString(Database.GetFingerprintModePrefKey(App.Kp2a.GetDb().Ioc), ""), out um); Enum.TryParse(_prefs.GetString(Database.GetFingerprintModePrefKey(App.Kp2a.CurrentDb.Ioc), ""), out um);
bool isFingerprintEnabled = (um == FingerprintUnlockMode.FullUnlock); bool isFingerprintEnabled = (um == FingerprintUnlockMode.FullUnlock);
string masterKeyKey = "MasterKey" + isFingerprintEnabled; string masterKeyKey = "MasterKey" + isFingerprintEnabled;
@@ -267,11 +267,11 @@ namespace keepass2android
List<string> applicableInfoTextKeys = new List<string> { masterKeyKey }; List<string> applicableInfoTextKeys = new List<string> { masterKeyKey };
if (App.Kp2a.GetFileStorage(App.Kp2a.GetDb().Ioc).UserShouldBackup) if (App.Kp2a.GetFileStorage(App.Kp2a.CurrentDb.Ioc).UserShouldBackup)
{ {
applicableInfoTextKeys.Add(backupKey); applicableInfoTextKeys.Add(backupKey);
} }
if (App.Kp2a.GetDb().Entries.Count > 15) if (App.Kp2a.CurrentDb.Entries.Count > 15)
{ {
applicableInfoTextKeys.Add(emergencyKey); applicableInfoTextKeys.Add(emergencyKey);
} }
@@ -378,10 +378,9 @@ namespace keepass2android
public void RefreshIfDirty() public void RefreshIfDirty()
{ {
Database db = App.Kp2a.GetDb(); if (App.Kp2a.DirtyGroups.Contains(Group))
if (db.Dirty.Contains(Group))
{ {
db.Dirty.Remove(Group); App.Kp2a.DirtyGroups.Remove(Group);
ListAdapter.NotifyDataSetChanged(); ListAdapter.NotifyDataSetChanged();
} }
@@ -407,7 +406,7 @@ namespace keepass2android
AppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent); AppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
// Likely the app has been killed exit the activity // Likely the app has been killed exit the activity
if (App.Kp2a.GetDb() == null) if (App.Kp2a.CurrentDb== null)
{ {
Finish(); Finish();
return; return;
@@ -458,7 +457,7 @@ namespace keepass2android
{ {
FindViewById(Resource.Id.hide_fingerprint_info).Click += (sender, args) => FindViewById(Resource.Id.hide_fingerprint_info).Click += (sender, args) =>
{ {
_prefs.Edit().PutBoolean(fingerprintinfohidden_prefskey + App.Kp2a.GetDb().CurrentFingerprintPrefKey, true).Commit(); _prefs.Edit().PutBoolean(fingerprintinfohidden_prefskey + App.Kp2a.CurrentDb.CurrentFingerprintPrefKey, true).Commit();
UpdateFingerprintInfo(); UpdateFingerprintInfo();
}; };
} }
@@ -627,7 +626,7 @@ namespace keepass2android
{ {
bool canShowFingerprintInfo = false; bool canShowFingerprintInfo = false;
bool disabledForDatabase = _prefs.GetBoolean(fingerprintinfohidden_prefskey + App.Kp2a.GetDb().CurrentFingerprintPrefKey, false); bool disabledForDatabase = _prefs.GetBoolean(fingerprintinfohidden_prefskey + App.Kp2a.CurrentDb.CurrentFingerprintPrefKey, false);
bool disabledForAll = _prefs.GetBoolean(fingerprintinfohidden_prefskey, false); bool disabledForAll = _prefs.GetBoolean(fingerprintinfohidden_prefskey, false);
if (!disabledForAll && !disabledForDatabase) if (!disabledForAll && !disabledForDatabase)
{ {
@@ -636,7 +635,7 @@ namespace keepass2android
if (fpModule.FingerprintManager != null && fpModule.FingerprintManager.IsHardwareDetected) if (fpModule.FingerprintManager != null && fpModule.FingerprintManager.IsHardwareDetected)
{ {
FingerprintUnlockMode um; FingerprintUnlockMode um;
Enum.TryParse(_prefs.GetString(Database.GetFingerprintModePrefKey(App.Kp2a.GetDb().Ioc), ""), out um); Enum.TryParse(_prefs.GetString(Database.GetFingerprintModePrefKey(App.Kp2a.CurrentDb.Ioc), ""), out um);
canShowFingerprintInfo = um == FingerprintUnlockMode.Disabled; canShowFingerprintInfo = um == FingerprintUnlockMode.Disabled;
} }
} }
@@ -667,8 +666,7 @@ namespace keepass2android
private void InsertElements() private void InsertElements()
{ {
MoveElementsTask moveElementsTask = (MoveElementsTask)AppTask; MoveElementsTask moveElementsTask = (MoveElementsTask)AppTask;
IEnumerable<IStructureItem> elementsToMove = IEnumerable<IStructureItem> elementsToMove = moveElementsTask.Uuids.Select(uuid => App.Kp2a.FindStructureItem(uuid));
moveElementsTask.Uuids.Select(uuid => App.Kp2a.GetDb().KpDatabase.RootGroup.FindObject(uuid, true, null));
@@ -690,7 +688,7 @@ namespace keepass2android
{ {
String name = Group.Name; String name = Group.Name;
String titleText; String titleText;
bool clickable = (Group != null) && (Group.IsVirtual == false) && (Group.ParentGroup != null); bool clickable = (Group != null) && (Group.IsVirtual == false) && ((Group.ParentGroup != null) || App.Kp2a.OpenDatabases.Count() > 1);
if (!String.IsNullOrEmpty(name)) if (!String.IsNullOrEmpty(name))
{ {
titleText = name; titleText = name;
@@ -715,9 +713,7 @@ namespace keepass2android
{ {
if (Group != null) if (Group != null)
{ {
Drawable drawable = App.Kp2a.GetDb().DrawableFactory.GetIconDrawable(this, App.Kp2a.GetDb().KpDatabase, Group.IconId, Group.CustomIconUuid, true);
SupportActionBar.SetDisplayShowHomeEnabled(true); SupportActionBar.SetDisplayShowHomeEnabled(true);
//SupportActionBar.SetIcon(drawable);
} }
} }
@@ -740,7 +736,8 @@ namespace keepass2android
var cursor = _suggestionsAdapter.Cursor; var cursor = _suggestionsAdapter.Cursor;
cursor.MoveToPosition(position); cursor.MoveToPosition(position);
string entryIdAsHexString = cursor.GetString(cursor.GetColumnIndexOrThrow(SearchManager.SuggestColumnIntentDataId)); string entryIdAsHexString = cursor.GetString(cursor.GetColumnIndexOrThrow(SearchManager.SuggestColumnIntentDataId));
EntryActivity.Launch(_activity, App.Kp2a.GetDb().Entries[new PwUuid(MemUtil.HexStringToByteArray(entryIdAsHexString))], -1, _activity.AppTask); var entryId = new PwUuid(MemUtil.HexStringToByteArray(entryIdAsHexString));
EntryActivity.Launch(_activity, App.Kp2a.FindDatabaseForEntryId(entryId).Entries[entryId], -1, _activity.AppTask);
return true; return true;
} }
@@ -830,35 +827,34 @@ namespace keepass2android
{ {
if (_syncItem != null) if (_syncItem != null)
{ {
if (App.Kp2a.GetDb().Ioc.IsLocalFile()) if (((App.Kp2a.OpenDatabases.Count() == 1) || (EntriesBelongToCurrentDatabaseOnly))
&& App.Kp2a.CurrentDb.Ioc.IsLocalFile())
_syncItem.SetVisible(false); _syncItem.SetVisible(false);
else else
_syncItem.SetVisible(!App.Kp2a.OfflineMode); _syncItem.SetVisible(!App.Kp2a.OfflineMode);
} }
if (App.Kp2a.GetFileStorage(App.Kp2a.GetDb().Ioc) is IOfflineSwitchable) if (((App.Kp2a.OpenDatabases.Count() == 1) || (EntriesBelongToCurrentDatabaseOnly))
&& (App.Kp2a.GetFileStorage(App.Kp2a.CurrentDb.Ioc) is IOfflineSwitchable))
{ {
if (_offlineItem != null) _offlineItem?.SetVisible(App.Kp2a.OfflineMode == false);
_offlineItem.SetVisible(App.Kp2a.OfflineMode == false); _onlineItem?.SetVisible(App.Kp2a.OfflineMode);
if (_onlineItem != null)
_onlineItem.SetVisible(App.Kp2a.OfflineMode);
} }
else else
{ {
if (_offlineItem != null) _offlineItem?.SetVisible(false);
_offlineItem.SetVisible(false); _onlineItem?.SetVisible(false);
if (_onlineItem != null)
_onlineItem.SetVisible(false);
} }
} }
catch (Exception e) catch (Exception e)
{ {
Kp2aLog.LogUnexpectedError(new Exception("Cannot UpdateOfflineModeMenu " + (App.Kp2a == null) + " " + ((App.Kp2a == null) || (App.Kp2a.GetDb() == null)) + " " + (((App.Kp2a == null) || (App.Kp2a.GetDb() == null) || (App.Kp2a.GetDb().Ioc == null)) + " " + (_syncItem != null) + " " + (_offlineItem != null) + " " + (_onlineItem != null)))); Kp2aLog.LogUnexpectedError(new Exception("Cannot UpdateOfflineModeMenu " + (App.Kp2a == null) + " " + ((App.Kp2a == null) || (App.Kp2a.CurrentDb== null)) + " " + (((App.Kp2a == null) || (App.Kp2a.CurrentDb== null) || (App.Kp2a.CurrentDb.Ioc == null)) + " " + (_syncItem != null) + " " + (_offlineItem != null) + " " + (_onlineItem != null))));
} }
} }
public abstract bool EntriesBelongToCurrentDatabaseOnly { get; }
public override bool OnPrepareOptionsMenu(IMenu menu) public override bool OnPrepareOptionsMenu(IMenu menu)
{ {
@@ -880,7 +876,7 @@ namespace keepass2android
case Resource.Id.menu_donate: case Resource.Id.menu_donate:
return Util.GotoDonateUrl(this); return Util.GotoDonateUrl(this);
case Resource.Id.menu_lock: case Resource.Id.menu_lock:
App.Kp2a.LockDatabase(); App.Kp2a.Lock();
return true; return true;
case Resource.Id.menu_search: case Resource.Id.menu_search:
@@ -906,8 +902,10 @@ namespace keepass2android
UpdateOfflineModeMenu(); UpdateOfflineModeMenu();
Synchronize(); Synchronize();
return true; return true;
case Resource.Id.menu_open_other_db:
AppTask.SetActivityResult(this, KeePass.ExitLoadAnotherDb);
Finish();
return true;
case Resource.Id.menu_sort: case Resource.Id.menu_sort:
ChangeSort(); ChangeSort();
return true; return true;
@@ -960,7 +958,7 @@ namespace keepass2android
private void Synchronize() private void Synchronize()
{ {
var filestorage = App.Kp2a.GetFileStorage(App.Kp2a.GetDb().Ioc); var filestorage = App.Kp2a.GetFileStorage(App.Kp2a.CurrentDb.Ioc);
RunnableOnFinish task; RunnableOnFinish task;
OnFinish onFinish = new ActionOnFinish(this, (success, message, activity) => OnFinish onFinish = new ActionOnFinish(this, (success, message, activity) =>
{ {
@@ -971,9 +969,9 @@ namespace keepass2android
BaseAdapter adapter = (BaseAdapter)((GroupBaseActivity)activity)?.ListAdapter; BaseAdapter adapter = (BaseAdapter)((GroupBaseActivity)activity)?.ListAdapter;
adapter?.NotifyDataSetChanged(); adapter?.NotifyDataSetChanged();
if (App.Kp2a.GetDb().OtpAuxFileIoc != null) if (App.Kp2a.CurrentDb.OtpAuxFileIoc != null)
{ {
var task2 = new SyncOtpAuxFile(this, App.Kp2a.GetDb().OtpAuxFileIoc); var task2 = new SyncOtpAuxFile(this, App.Kp2a.CurrentDb.OtpAuxFileIoc);
new ProgressTask(App.Kp2a, activity, task2).Run(true); new ProgressTask(App.Kp2a, activity, task2).Run(true);
} }
}); });
@@ -1022,10 +1020,10 @@ namespace keepass2android
ActivityCompat.InvalidateOptionsMenu(this); ActivityCompat.InvalidateOptionsMenu(this);
// Mark all groups as dirty now to refresh them on load // Mark all groups as dirty now to refresh them on load
Database db = App.Kp2a.GetDb();
db.MarkAllGroupsAsDirty(); App.Kp2a.MarkAllGroupsAsDirty();
// We'll manually refresh this group so we can remove it // We'll manually refresh this group so we can remove it
db.Dirty.Remove(Group); App.Kp2a.DirtyGroups.Remove(Group);
// Tell the adapter to refresh it's list // Tell the adapter to refresh it's list
@@ -1082,7 +1080,7 @@ namespace keepass2android
Toast.MakeText(ActiveActivity, "Unrecoverable error: " + Message, ToastLength.Long).Show(); Toast.MakeText(ActiveActivity, "Unrecoverable error: " + Message, ToastLength.Long).Show();
}); });
App.Kp2a.LockDatabase(false); App.Kp2a.Lock(false);
} }
} }
@@ -1133,9 +1131,9 @@ namespace keepass2android
MoveElementsTask moveElementsTask = (MoveElementsTask)AppTask; MoveElementsTask moveElementsTask = (MoveElementsTask)AppTask;
foreach (var uuid in moveElementsTask.Uuids) foreach (var uuid in moveElementsTask.Uuids)
{ {
IStructureItem elementToMove = App.Kp2a.GetDb().KpDatabase.RootGroup.FindObject(uuid, true, null); IStructureItem elementToMove = App.Kp2a.FindStructureItem(uuid);
if (elementToMove.ParentGroup != Group) if (elementToMove.ParentGroup != Group)
App.Kp2a.GetDb().Dirty.Add(elementToMove.ParentGroup); App.Kp2a.DirtyGroups.Add(elementToMove.ParentGroup);
} }
} }
catch (Exception e) catch (Exception e)
@@ -1167,7 +1165,7 @@ namespace keepass2android
base.OnActivityCreated(savedInstanceState); base.OnActivityCreated(savedInstanceState);
ListView.SetMultiChoiceModeListener(this); ListView.SetMultiChoiceModeListener(this);
if (App.Kp2a.GetDb().CanWrite) if (App.Kp2a.OpenDatabases.Any(db => db.CanWrite))
{ {
ListView.ChoiceMode = ChoiceMode.MultipleModal; ListView.ChoiceMode = ChoiceMode.MultipleModal;
@@ -1221,13 +1219,10 @@ namespace keepass2android
{ {
case Resource.Id.menu_delete: case Resource.Id.menu_delete:
DeleteMultipleItems((GroupBaseActivity)Activity, checkedItems, new GroupBaseActivity.RefreshTask(handler, ((GroupBaseActivity)Activity)), App.Kp2a);
DeleteMultipleItems task = new DeleteMultipleItems((GroupBaseActivity)Activity, App.Kp2a.GetDb(), checkedItems,
new GroupBaseActivity.RefreshTask(handler, ((GroupBaseActivity)Activity)), App.Kp2a);
task.Start();
break; break;
case Resource.Id.menu_move: case Resource.Id.menu_move:
var navMove = new NavigateToFolderAndLaunchMoveElementTask(checkedItems.First().ParentGroup, checkedItems.Select(i => i.Uuid).ToList(), ((GroupBaseActivity)Activity).IsSearchResult); var navMove = new NavigateToFolderAndLaunchMoveElementTask(App.Kp2a.CurrentDb, checkedItems.First().ParentGroup, checkedItems.Select(i => i.Uuid).ToList(), ((GroupBaseActivity)Activity).IsSearchResult);
((GroupBaseActivity)Activity).StartTask(navMove); ((GroupBaseActivity)Activity).StartTask(navMove);
break; break;
case Resource.Id.menu_copy: case Resource.Id.menu_copy:
@@ -1240,7 +1235,7 @@ namespace keepass2android
break; break;
case Resource.Id.menu_navigate: case Resource.Id.menu_navigate:
NavigateToFolder navNavigate = new NavigateToFolder(checkedItems.First().ParentGroup, true); NavigateToFolder navNavigate = new NavigateToFolder(App.Kp2a.CurrentDb, checkedItems.First().ParentGroup, true);
((GroupBaseActivity)Activity).StartTask(navNavigate); ((GroupBaseActivity)Activity).StartTask(navNavigate);
break; break;
case Resource.Id.menu_edit: case Resource.Id.menu_edit:
@@ -1378,6 +1373,66 @@ namespace keepass2android
{ {
return IsOnlyOneItemChecked() && !IsOnlyOneGroupChecked(); return IsOnlyOneItemChecked() && !IsOnlyOneGroupChecked();
} }
public void DeleteMultipleItems(GroupBaseActivity activity, List<IStructureItem> checkedItems, OnFinish onFinish, Kp2aApp app)
{
if (checkedItems.Any() == false)
return;
//sort checkedItems by database
List<KeyValuePair<Database, List<IStructureItem>>> itemsForDatabases =
new List<KeyValuePair<Database, List<IStructureItem>>>();
foreach (var item in checkedItems)
{
var db = app.FindDatabaseForEntryId(item.Uuid) ?? app.FindDatabaseForGroupId(item.Uuid);
if (db != null)
{
bool foundDatabase = false;
foreach (var listEntry in itemsForDatabases)
{
if (listEntry.Key == db)
{
foundDatabase = true;
listEntry.Value.Add(item);
break;
}
}
if (!foundDatabase)
{
itemsForDatabases.Add(new KeyValuePair<Database, List<IStructureItem>>(db, new List<IStructureItem> { item }));
}
}
}
int dbIndex = 0;
Action<bool, string, Activity> action = null;
action = (success, message, activeActivity) =>
{
if (success)
{
dbIndex++;
if (dbIndex == itemsForDatabases.Count)
{
onFinish.SetResult(true);
onFinish.Run();
return;
}
new DeleteMultipleItemsFromOneDatabase(activity, itemsForDatabases[dbIndex].Key,
itemsForDatabases[dbIndex].Value, new ActionOnFinish(activeActivity, (b, s, activity1) => action(b, s, activity1)), app)
.Start();
}
else
{
onFinish.SetResult(false, message, null);
}
};
new DeleteMultipleItemsFromOneDatabase(activity, itemsForDatabases[dbIndex].Key,
itemsForDatabases[dbIndex].Value, new ActionOnFinish(activity, (b, s, activity1) => action(b, s, activity1)), app)
.Start();
}
} }
} }

View File

@@ -90,7 +90,7 @@ namespace keepass2android
}; };
_selectedIconId = (int) PwIcon.FolderOpen; _selectedIconId = (int) PwIcon.FolderOpen;
iconButton.SetImageDrawable(App.Kp2a.GetDb().DrawableFactory.GetIconDrawable(this, App.Kp2a.GetDb().KpDatabase, (PwIcon)_selectedIconId, null, true)); iconButton.SetImageDrawable(App.Kp2a.CurrentDb.DrawableFactory.GetIconDrawable(this, App.Kp2a.CurrentDb.KpDatabase, (PwIcon)_selectedIconId, null, true));
Button okButton = (Button)FindViewById (Resource.Id.ok); Button okButton = (Button)FindViewById (Resource.Id.ok);
okButton.Click += (sender, e) => { okButton.Click += (sender, e) => {
@@ -118,12 +118,12 @@ namespace keepass2android
if (Intent.HasExtra(KeyGroupUuid)) if (Intent.HasExtra(KeyGroupUuid))
{ {
string groupUuid = Intent.Extras.GetString(KeyGroupUuid); string groupUuid = Intent.Extras.GetString(KeyGroupUuid);
_groupToEdit = App.Kp2a.GetDb().Groups[new PwUuid(MemUtil.HexStringToByteArray(groupUuid))]; _groupToEdit = App.Kp2a.CurrentDb.Groups[new PwUuid(MemUtil.HexStringToByteArray(groupUuid))];
_selectedIconId = (int) _groupToEdit.IconId; _selectedIconId = (int) _groupToEdit.IconId;
_selectedCustomIconId = _groupToEdit.CustomIconUuid; _selectedCustomIconId = _groupToEdit.CustomIconUuid;
TextView nameField = (TextView)FindViewById(Resource.Id.group_name); TextView nameField = (TextView)FindViewById(Resource.Id.group_name);
nameField.Text = _groupToEdit.Name; nameField.Text = _groupToEdit.Name;
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iconButton, this, App.Kp2a.GetDb().KpDatabase, _groupToEdit.IconId, _groupToEdit.CustomIconUuid, false); App.Kp2a.CurrentDb.DrawableFactory.AssignDrawableTo(iconButton, this, App.Kp2a.CurrentDb.KpDatabase, _groupToEdit.IconId, _groupToEdit.CustomIconUuid, false);
SetTitle(Resource.String.edit_group_title); SetTitle(Resource.String.edit_group_title);
} }
else else
@@ -156,7 +156,7 @@ namespace keepass2android
_selectedCustomIconId = PwUuid.Zero; _selectedCustomIconId = PwUuid.Zero;
ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button); ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button);
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(currIconButton, this, App.Kp2a.GetDb().KpDatabase, (PwIcon) _selectedIconId, _selectedCustomIconId, false); App.Kp2a.CurrentDb.DrawableFactory.AssignDrawableTo(currIconButton, this, App.Kp2a.CurrentDb.KpDatabase, (PwIcon) _selectedIconId, _selectedCustomIconId, false);
break; break;
} }
} }

View File

@@ -51,7 +51,7 @@ namespace keepass2android
SetContentView(Resource.Layout.icon_picker); SetContentView(Resource.Layout.icon_picker);
GridView currIconGridView = (GridView)FindViewById(Resource.Id.IconGridView); GridView currIconGridView = (GridView)FindViewById(Resource.Id.IconGridView);
currIconGridView.Adapter = new ImageAdapter(this, App.Kp2a.GetDb().KpDatabase); currIconGridView.Adapter = new ImageAdapter(this, App.Kp2a.CurrentDb.KpDatabase);
currIconGridView.ItemClick += (sender, e) => currIconGridView.ItemClick += (sender, e) =>
{ {
@@ -134,7 +134,7 @@ namespace keepass2android
bitmap.Compress(Bitmap.CompressFormat.Png, 90, ms); bitmap.Compress(Bitmap.CompressFormat.Png, 90, ms);
PwCustomIcon pwci = new PwCustomIcon(new PwUuid(true), ms.ToArray()); PwCustomIcon pwci = new PwCustomIcon(new PwUuid(true), ms.ToArray());
App.Kp2a.GetDb().KpDatabase.CustomIcons.Add(pwci); App.Kp2a.CurrentDb.KpDatabase.CustomIcons.Add(pwci);
} }
var gridView = ((GridView)FindViewById(Resource.Id.IconGridView)); var gridView = ((GridView)FindViewById(Resource.Id.IconGridView));
@@ -198,8 +198,7 @@ namespace keepass2android
if (position < (int)PwIcon.Count) if (position < (int)PwIcon.Count)
{ {
tv.Text = "" + position; tv.Text = "" + position;
var drawable = App.Kp2a.GetDb() var drawable = App.Kp2a.CurrentDb .DrawableFactory.GetIconDrawable(_act, App.Kp2a.CurrentDb.KpDatabase, (KeePassLib.PwIcon) position, null, false);
.DrawableFactory.GetIconDrawable(_act, App.Kp2a.GetDb().KpDatabase, (KeePassLib.PwIcon) position, null, false);
drawable = new BitmapDrawable(Util.DrawableToBitmap(drawable)); drawable = new BitmapDrawable(Util.DrawableToBitmap(drawable));
iv.SetImageDrawable(drawable); iv.SetImageDrawable(drawable);
//App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iv, _act, App.Kp2a.GetDb().KpDatabase, (KeePassLib.PwIcon) position, null, false); //App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iv, _act, App.Kp2a.GetDb().KpDatabase, (KeePassLib.PwIcon) position, null, false);

View File

@@ -317,7 +317,7 @@ namespace keepass2android
SetContentView(Resource.Layout.ImageViewActivity); SetContentView(Resource.Layout.ImageViewActivity);
var uuid = new PwUuid(MemUtil.HexStringToByteArray(Intent.GetStringExtra("EntryId"))); var uuid = new PwUuid(MemUtil.HexStringToByteArray(Intent.GetStringExtra("EntryId")));
string key = Intent.GetStringExtra("EntryKey"); string key = Intent.GetStringExtra("EntryKey");
var binary = App.Kp2a.GetDb().Entries[uuid].Binaries.Get(key); var binary = App.Kp2a.FindDatabaseForEntryId(uuid).Entries[uuid].Binaries.Get(key);
SupportActionBar.Title = key; SupportActionBar.Title = key;
byte[] pbdata = binary.ReadData(); byte[] pbdata = binary.ReadData();

View File

@@ -38,8 +38,8 @@ using String = System.String;
* Keepass2Android comprises quite a number of different activities and entry points: The app can be started * Keepass2Android comprises quite a number of different activities and entry points: The app can be started
* using the launcher icon (-> Activity "Keepass"), or by sending a URL (-> FileSelect), opening a .kdb(x)-file (->Password), * using the launcher icon (-> Activity "Keepass"), or by sending a URL (-> FileSelect), opening a .kdb(x)-file (->Password),
* swiping a YubikeyNEO (NfcOtpActivity). * swiping a YubikeyNEO (NfcOtpActivity).
* While the database is closed, there is only one activity on the stack: Keepass -> FileSelect <-> Password. * There is either only the KeePass activity on stack (no db loaded then) or the first activity
* After opening an database (in Password), Password is always the root of the stack (exception: after creating a database, * After opening a database (in Password), Password is always the root of the stack (exception: after creating a database,
* FileSelect is the root without Password being open). * FileSelect is the root without Password being open).
* Another exception: QueryCredentialsActivity is root of the stack if an external app is querying credentials. * Another exception: QueryCredentialsActivity is root of the stack if an external app is querying credentials.
* QueryCredentialsActivity checks the plugin access permissions, then launches FileSelectActivity (which starts * QueryCredentialsActivity checks the plugin access permissions, then launches FileSelectActivity (which starts
@@ -86,8 +86,10 @@ namespace keepass2android
public const Result ExitClose = Result.FirstUser + 7; public const Result ExitClose = Result.FirstUser + 7;
public const Result ExitFileStorageSelectionOk = Result.FirstUser + 8; public const Result ExitFileStorageSelectionOk = Result.FirstUser + 8;
public const Result ResultOkPasswordGenerator = Result.FirstUser + 9; public const Result ResultOkPasswordGenerator = Result.FirstUser + 9;
public const Result ExitLoadAnotherDb = Result.FirstUser + 10;
public const string TagsKey = "@tags";
public const string TagsKey = "@tags";
public const string OverrideUrlKey = "@override"; public const string OverrideUrlKey = "@override";
public const string ExpDateKey = "@exp_date"; public const string ExpDateKey = "@exp_date";

View File

@@ -38,7 +38,7 @@ namespace keepass2android
return res; return res;
} }
private const string EtmTemplateUuid = "_etm_template_uuid"; public const string EtmTemplateUuid = "_etm_template_uuid";
private const string EtmTitle = "_etm_title_"; private const string EtmTitle = "_etm_title_";
private readonly Database _db; private readonly Database _db;
private readonly PwEntry _entry; private readonly PwEntry _entry;

View File

@@ -51,7 +51,7 @@ namespace keepass2android
{ {
base.OnResume(); base.OnResume();
Kp2aLog.Log(ClassName+".OnResume"); Kp2aLog.Log(ClassName+".OnResume");
if (App.Kp2a.GetDb() == null) if (App.Kp2a.CurrentDb== null)
{ {
Kp2aLog.Log(" DB null"); Kp2aLog.Log(" DB null");
} }

View File

@@ -63,7 +63,7 @@ namespace keepass2android
} }
_ioc = App.Kp2a.GetDb().Ioc; _ioc = App.Kp2a.CurrentDb.Ioc;
if (Intent.GetBooleanExtra(NoLockCheck, false)) if (Intent.GetBooleanExtra(NoLockCheck, false))
return; return;
@@ -106,10 +106,13 @@ namespace keepass2android
if (Intent.GetBooleanExtra(NoLockCheck, false)) if (Intent.GetBooleanExtra(NoLockCheck, false))
return; return;
if (TimeoutHelper.CheckShutdown(this, _ioc)) if (TimeoutHelper.CheckDbChanged(this, _ioc))
return; {
Finish();
return;
}
//todo: it seems like OnResume can be called after dismissing a dialog, e.g. the Delete-permanently-Dialog. //todo: it seems like OnResume can be called after dismissing a dialog, e.g. the Delete-permanently-Dialog.
//in this case the following check might run in parallel with the check performed during the SaveDb check (triggered after the //in this case the following check might run in parallel with the check performed during the SaveDb check (triggered after the
//aforementioned dialog is closed) which can cause odd behavior. However, this is a rare case and hard to resolve so this is currently //aforementioned dialog is closed) which can cause odd behavior. However, this is a rare case and hard to resolve so this is currently
//accepted. (If the user clicks cancel on the reload-dialog, everything will work.) //accepted. (If the user clicks cancel on the reload-dialog, everything will work.)

View File

@@ -51,7 +51,7 @@ namespace keepass2android
Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure); Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
} }
_ioc = App.Kp2a.GetDb().Ioc; _ioc = App.Kp2a.CurrentDb.Ioc;
_intentReceiver = new LockCloseListActivityBroadcastReceiver(this); _intentReceiver = new LockCloseListActivityBroadcastReceiver(this);
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
@@ -73,10 +73,13 @@ namespace keepass2android
base.OnResume(); base.OnResume();
_design.ReapplyTheme(); _design.ReapplyTheme();
if (TimeoutHelper.CheckShutdown(this, _ioc)) if (TimeoutHelper.CheckDbChanged(this, _ioc))
return; {
Finish();
return;
}
//todo: see LockCloseActivity.OnResume //todo: see LockCloseActivity.OnResume
App.Kp2a.CheckForOpenFileChanged(this); App.Kp2a.CheckForOpenFileChanged(this);
} }

View File

@@ -43,7 +43,7 @@ namespace keepass2android
{ {
base.OnStart(); base.OnStart();
var xcKey = App.Kp2a.GetDb()?.KpDatabase.MasterKey.GetUserKey<ChallengeXCKey>(); var xcKey = App.Kp2a.CurrentDb?.KpDatabase.MasterKey.GetUserKey<ChallengeXCKey>();
if (xcKey != null) if (xcKey != null)
{ {
xcKey.Activity = this; xcKey.Activity = this;
@@ -58,7 +58,7 @@ namespace keepass2android
protected override void OnStop() protected override void OnStop()
{ {
base.OnStop(); base.OnStop();
var xcKey = App.Kp2a.GetDb()?.KpDatabase.MasterKey.GetUserKey<ChallengeXCKey>(); var xcKey = App.Kp2a.CurrentDb?.KpDatabase.MasterKey.GetUserKey<ChallengeXCKey>();
if (xcKey != null) if (xcKey != null)
{ {
//don't store a pointer to this activity in the static database object to avoid memory leak //don't store a pointer to this activity in the static database object to avoid memory leak

View File

@@ -32,7 +32,7 @@ namespace keepass2android
protected override void OnCreate(Bundle savedInstanceState) protected override void OnCreate(Bundle savedInstanceState)
{ {
base.OnCreate(savedInstanceState); base.OnCreate(savedInstanceState);
_ioc = App.Kp2a.GetDb().Ioc; _ioc = App.Kp2a.CurrentDb.Ioc;
_intentReceiver = new LockingClosePreferenceActivityBroadcastReceiver(this); _intentReceiver = new LockingClosePreferenceActivityBroadcastReceiver(this);
@@ -44,7 +44,11 @@ namespace keepass2android
protected override void OnResume() { protected override void OnResume() {
base.OnResume(); base.OnResume();
TimeoutHelper.CheckShutdown(this, _ioc); if (TimeoutHelper.CheckDbChanged(this, _ioc))
{
Finish();
return;
}
} }

View File

@@ -93,15 +93,7 @@ namespace keepass2android
return; return;
} }
if (App.Kp2a.GetDb() != null) StartActivity(i);
{
Toast.MakeText(this, GetString(Resource.String.otp_discarded_because_db_open), ToastLength.Long).Show();
}
else
{
StartActivity(i);
}
Finish(); Finish();
} }

View File

@@ -737,12 +737,6 @@ namespace keepass2android
} }
} }
if (App.Kp2a.GetDb()?.Ioc != null && App.Kp2a.GetDb().Ioc.GetDisplayName() != _ioConnection.GetDisplayName())
{
// A different database is currently loaded, unload it before loading the new one requested
App.Kp2a.LockDatabase(false);
}
SetContentView(Resource.Layout.password); SetContentView(Resource.Layout.password);
InitializeToolbar(); InitializeToolbar();
@@ -807,6 +801,14 @@ namespace keepass2android
if ((int)Build.VERSION.SdkInt >= 23) if ((int)Build.VERSION.SdkInt >= 23)
RequestPermissions(new[] { Manifest.Permission.UseFingerprint }, FingerprintPermissionRequestCode); RequestPermissions(new[] { Manifest.Permission.UseFingerprint }, FingerprintPermissionRequestCode);
var matchingOpenDb = App.Kp2a.OpenDatabases.FirstOrDefault(db => db.Ioc.IsSameFileAs(_ioConnection));
if (matchingOpenDb != null)
{
App.Kp2a.CurrentDb = matchingOpenDb;
Finish();
}
} }
private void InitializeToolbarCollapsing() private void InitializeToolbarCollapsing()
@@ -1473,9 +1475,7 @@ namespace keepass2android
: new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, GetKeyProviderString(), onFinish); : new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, GetKeyProviderString(), onFinish);
_loadDbFileTask = null; // prevent accidental re-use _loadDbFileTask = null; // prevent accidental re-use
SetNewDefaultFile(); new ProgressTask(App.Kp2a, this, task).Run();
new ProgressTask(App.Kp2a, this, task).Run();
} }
catch (Exception e) catch (Exception e)
{ {
@@ -1596,35 +1596,7 @@ namespace keepass2android
base.OnPause(); base.OnPause();
} }
private void SetNewDefaultFile() protected override void OnStart()
{
//Don't allow the current file to be the default if we don't have stored credentials
bool makeFileDefault;
if ((_ioConnection.IsLocalFile() == false) && (_ioConnection.CredSaveMode != IOCredSaveMode.SaveCred))
{
makeFileDefault = false;
}
else
{
makeFileDefault = true;
}
String newDefaultFileName;
if (makeFileDefault)
{
newDefaultFileName = _ioConnection.Path;
}
else
{
newDefaultFileName = "";
}
ISharedPreferencesEditor editor = _prefs.Edit();
editor.PutString(KeyDefaultFilename, newDefaultFileName);
EditorCompat.Apply(editor);
}
protected override void OnStart()
{ {
base.OnStart(); base.OnStart();
_starting = true; _starting = true;
@@ -1815,34 +1787,27 @@ namespace keepass2android
//use !performingLoad to make sure we're not already loading the database (after ActivityResult from File-Prepare-Activity; this would cause _loadDbFileTask to exist when we reload later!) //use !performingLoad to make sure we're not already loading the database (after ActivityResult from File-Prepare-Activity; this would cause _loadDbFileTask to exist when we reload later!)
if ( !IsFinishing && !_performingLoad) if ( !IsFinishing && !_performingLoad)
{ {
if (App.Kp2a.DatabaseIsUnlocked)
{
Finish();
}
else if (App.Kp2a.QuickUnlockEnabled && App.Kp2a.QuickLocked)
{
Finish();
}
else
{
// OnResume is run every time the activity comes to the foreground. This code should only run when the activity is started (OnStart), but must
// be run in OnResume rather than OnStart so that it always occurrs after OnActivityResult (when re-creating a killed activity, OnStart occurs before OnActivityResult)
if (_starting)
{
_starting = false;
//database not yet loaded. // OnResume is run every time the activity comes to the foreground. This code should only run when the activity is started (OnStart), but must
// be run in OnResume rather than OnStart so that it always occurrs after OnActivityResult (when re-creating a killed activity, OnStart occurs before OnActivityResult)
if (_starting)
{
_starting = false;
//database not yet loaded.
//check if pre-loading is enabled but wasn't started yet:
if (_loadDbFileTask == null &&
_prefs.GetBoolean(GetString(Resource.String.PreloadDatabaseEnabled_key), true))
{
// Create task to kick off file loading while the user enters the password
_loadDbFileTask = Task.Factory.StartNew(PreloadDbFile);
_loadDbTaskOffline = App.Kp2a.OfflineMode;
}
}
//check if pre-loading is enabled but wasn't started yet:
if (_loadDbFileTask == null && _prefs.GetBoolean(GetString(Resource.String.PreloadDatabaseEnabled_key), true))
{
// Create task to kick off file loading while the user enters the password
_loadDbFileTask = Task.Factory.StartNew(PreloadDbFile);
_loadDbTaskOffline = App.Kp2a.OfflineMode;
}
}
}
} }
if (compositeKeyForImmediateLoad != null) if (compositeKeyForImmediateLoad != null)
@@ -2049,6 +2014,7 @@ namespace keepass2android
_act.BroadcastOpenDatabase(); _act.BroadcastOpenDatabase();
_act.InvalidCompositeKeyCount = 0; _act.InvalidCompositeKeyCount = 0;
_act.LoadingErrorCount = 0; _act.LoadingErrorCount = 0;
_act.Finish();
GC.Collect(); // Ensure temporary memory used while loading is collected GC.Collect(); // Ensure temporary memory used while loading is collected
@@ -2193,7 +2159,7 @@ namespace keepass2android
if (!OathHotpKeyProv.CreateAuxFile(_act._otpInfo, ctx, _act._otpAuxIoc)) if (!OathHotpKeyProv.CreateAuxFile(_act._otpInfo, ctx, _act._otpAuxIoc))
Toast.MakeText(_act, _act.GetString(Resource.String.ErrorUpdatingOtpAuxFile), ToastLength.Long).Show(); Toast.MakeText(_act, _act.GetString(Resource.String.ErrorUpdatingOtpAuxFile), ToastLength.Long).Show();
App.Kp2a.GetDb().OtpAuxFileIoc = _act._otpAuxIoc;
} }
catch (Exception e) catch (Exception e)
{ {
@@ -2206,7 +2172,14 @@ namespace keepass2android
base.Run(); base.Run();
} if (success)
{
App.Kp2a.CurrentDb.OtpAuxFileIoc = _act._otpAuxIoc;
}
}
} }
private class PasswordActivityBroadcastReceiver : BroadcastReceiver private class PasswordActivityBroadcastReceiver : BroadcastReceiver
{ {

View File

@@ -49,8 +49,8 @@ namespace keepass2android
//if launched from history, don't re-use the task. Proceed to FileSelect instead. //if launched from history, don't re-use the task. Proceed to FileSelect instead.
if (Intent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory)) if (Intent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory))
{ {
Kp2aLog.Log("Forwarding to FileSelect. QueryCredentialsActivity started from history."); Kp2aLog.Log("Forwarding to SelectCurrentDbActivity. QueryCredentialsActivity started from history.");
Intent intent = new Intent(this, typeof(FileSelectActivity)); Intent intent = new Intent(this, typeof(SelectCurrentDbActivity));
intent.AddFlags(ActivityFlags.ForwardResult); intent.AddFlags(ActivityFlags.ForwardResult);
StartActivity(intent); StartActivity(intent);
Finish(); Finish();
@@ -135,9 +135,9 @@ namespace keepass2android
private void StartQuery() private void StartQuery()
{ {
//launch FileSelectActivity (which is root of the stack (exception: we're even below!)) with the appropriate task. //launch SelectCurrentDbActivity (which is root of the stack (exception: we're even below!)) with the appropriate task.
//will return the results later //will return the results later
Intent i = new Intent(this, typeof (FileSelectActivity)); Intent i = new Intent(this, typeof (SelectCurrentDbActivity));
//don't show user notifications when an entry is opened. //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};
task.ToIntent(i); task.ToIntent(i);
@@ -185,7 +185,7 @@ namespace keepass2android
} }
//return credentials to caller: //return credentials to caller:
Intent credentialData = new Intent(); Intent credentialData = new Intent();
PluginHost.AddEntryToIntent(credentialData, App.Kp2a.GetDb().LastOpenedEntry); PluginHost.AddEntryToIntent(credentialData, App.Kp2a.LastOpenedEntry);
credentialData.PutExtra(Strings.ExtraQueryString,_requestedUrl); credentialData.PutExtra(Strings.ExtraQueryString,_requestedUrl);
SetResult(Result.Ok, credentialData); SetResult(Result.Ok, credentialData);
Finish(); Finish();

View File

@@ -16,6 +16,7 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll.
*/ */
using System; using System;
using System.Linq;
using Android; using Android;
using Android.App; using Android.App;
using Android.Content; using Android.Content;
@@ -64,7 +65,7 @@ namespace keepass2android
Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure); Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
} }
_ioc = App.Kp2a.GetDb().Ioc; _ioc = App.Kp2a.GetDbForQuickUnlock().Ioc;
if (_ioc == null) if (_ioc == null)
{ {
@@ -81,10 +82,10 @@ namespace keepass2android
var collapsingToolbar = FindViewById<CollapsingToolbarLayout>(Resource.Id.collapsing_toolbar); var collapsingToolbar = FindViewById<CollapsingToolbarLayout>(Resource.Id.collapsing_toolbar);
collapsingToolbar.SetTitle(GetString(Resource.String.QuickUnlock_prefs)); collapsingToolbar.SetTitle(GetString(Resource.String.QuickUnlock_prefs));
if (App.Kp2a.GetDb().KpDatabase.Name != "") if (App.Kp2a.GetDbForQuickUnlock().KpDatabase.Name != "")
{ {
FindViewById(Resource.Id.filename_label).Visibility = ViewStates.Visible; FindViewById(Resource.Id.filename_label).Visibility = ViewStates.Visible;
((TextView) FindViewById(Resource.Id.filename_label)).Text = App.Kp2a.GetDb().KpDatabase.Name; ((TextView) FindViewById(Resource.Id.filename_label)).Text = App.Kp2a.GetDbForQuickUnlock().KpDatabase.Name;
} }
else else
{ {
@@ -134,7 +135,7 @@ namespace keepass2android
btnLock.Text = btnLock.Text.Replace("<22>", "ss"); btnLock.Text = btnLock.Text.Replace("<22>", "ss");
btnLock.Click += (object sender, EventArgs e) => btnLock.Click += (object sender, EventArgs e) =>
{ {
App.Kp2a.LockDatabase(false); App.Kp2a.Lock(false);
Finish(); Finish();
}; };
pwd.EditorAction += (sender, args) => pwd.EditorAction += (sender, args) =>
@@ -244,7 +245,7 @@ namespace keepass2android
try try
{ {
FingerprintUnlockMode um; FingerprintUnlockMode um;
Enum.TryParse(PreferenceManager.GetDefaultSharedPreferences(this).GetString(App.Kp2a.GetDb().CurrentFingerprintModePrefKey, ""), out um); Enum.TryParse(PreferenceManager.GetDefaultSharedPreferences(this).GetString(App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintModePrefKey, ""), out um);
btn.Visibility = (um != FingerprintUnlockMode.Disabled) ? ViewStates.Visible : ViewStates.Gone; btn.Visibility = (um != FingerprintUnlockMode.Disabled) ? ViewStates.Visible : ViewStates.Gone;
if (um == FingerprintUnlockMode.Disabled) if (um == FingerprintUnlockMode.Disabled)
@@ -258,10 +259,10 @@ namespace keepass2android
FingerprintModule fpModule = new FingerprintModule(this); FingerprintModule fpModule = new FingerprintModule(this);
Kp2aLog.Log("fpModule.FingerprintManager.IsHardwareDetected=" + fpModule.FingerprintManager.IsHardwareDetected); Kp2aLog.Log("fpModule.FingerprintManager.IsHardwareDetected=" + fpModule.FingerprintManager.IsHardwareDetected);
if (fpModule.FingerprintManager.IsHardwareDetected) //see FingerprintSetupActivity if (fpModule.FingerprintManager.IsHardwareDetected) //see FingerprintSetupActivity
_fingerprintIdentifier = new FingerprintDecryption(fpModule, App.Kp2a.GetDb().CurrentFingerprintPrefKey, this, _fingerprintIdentifier = new FingerprintDecryption(fpModule, App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey, this,
App.Kp2a.GetDb().CurrentFingerprintPrefKey); App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey);
} }
if ((_fingerprintIdentifier == null) && (!FingerprintDecryption.IsSetUp(this, App.Kp2a.GetDb().CurrentFingerprintPrefKey))) if ((_fingerprintIdentifier == null) && (!FingerprintDecryption.IsSetUp(this, App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey)))
{ {
try try
{ {
@@ -321,15 +322,7 @@ namespace keepass2android
_fingerprintIdentifier = null; _fingerprintIdentifier = null;
} }
private void ClearFingerprintUnlockData() private void OnUnlock(int quickUnlockLength, EditText pwd)
{
ISharedPreferencesEditor edit = PreferenceManager.GetDefaultSharedPreferences(this).Edit();
edit.PutString(App.Kp2a.GetDb().CurrentFingerprintPrefKey, "");
edit.PutString(App.Kp2a.GetDb().CurrentFingerprintModePrefKey, FingerprintUnlockMode.Disabled.ToString());
edit.Commit();
}
private void OnUnlock(int quickUnlockLength, EditText pwd)
{ {
var expectedPasswordPart = ExpectedPasswordPart; var expectedPasswordPart = ExpectedPasswordPart;
if (pwd.Text == expectedPasswordPart) if (pwd.Text == expectedPasswordPart)
@@ -340,7 +333,7 @@ namespace keepass2android
else else
{ {
Kp2aLog.Log("QuickUnlock not successful!"); Kp2aLog.Log("QuickUnlock not successful!");
App.Kp2a.LockDatabase(false); App.Kp2a.Lock(false);
Toast.MakeText(this, GetString(Resource.String.QuickUnlock_fail), ToastLength.Long).Show(); Toast.MakeText(this, GetString(Resource.String.QuickUnlock_fail), ToastLength.Long).Show();
} }
Finish(); Finish();
@@ -350,7 +343,7 @@ namespace keepass2android
{ {
get get
{ {
KcpPassword kcpPassword = (KcpPassword) App.Kp2a.GetDb().KpDatabase.MasterKey.GetUserKey(typeof (KcpPassword)); KcpPassword kcpPassword = (KcpPassword) App.Kp2a.GetDbForQuickUnlock().KpDatabase.MasterKey.GetUserKey(typeof (KcpPassword));
String password = kcpPassword.Password.ReadString(); String password = kcpPassword.Password.ReadString();
var passwordStringInfo = new System.Globalization.StringInfo(password); var passwordStringInfo = new System.Globalization.StringInfo(password);
@@ -427,7 +420,7 @@ namespace keepass2android
private void CheckIfUnloaded() private void CheckIfUnloaded()
{ {
if (App.Kp2a.GetDb() == null) if (App.Kp2a.OpenDatabases.Any() == false)
{ {
Finish(); Finish();
} }

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:background="@drawable/splash_bg_selector"
android:fitsSystemWindows="true"
android:layout_height="fill_parent"
android:gravity="center_horizontal">
<android.support.v7.widget.Toolbar
android:id="@+id/mytoolbar"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:titleTextStyle="@style/MyTitleTextStyle"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:minHeight="?attr/actionBarSize"
android:background="#00000000" />
<GridView
android:id="@+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="16dp"
android:background="@drawable/storagetype_grid_bg"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:layout_marginTop="0dp"
android:columnWidth="140dp"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center" />
</LinearLayout>

View File

@@ -57,11 +57,16 @@
app:showAsAction="never" app:showAsAction="never"
/> />
<item android:id="@+id/menu_sort" <item android:id="@+id/menu_sort"
android:icon="@android:drawable/ic_menu_sort_by_size" android:icon="@android:drawable/ic_menu_sort_by_size"
android:title="@string/sort_menu" android:title="@string/sort_menu"
app:showAsAction="never" app:showAsAction="never"
/> />
<item android:id="@+id/menu_open_other_db"
android:title="@string/open_other_db"
app:showAsAction="never"
/>
</menu> </menu>

View File

@@ -63,6 +63,7 @@
<string name="unlock_database_title">Unlock database</string> <string name="unlock_database_title">Unlock database</string>
<string name="brackets">Brackets</string> <string name="brackets">Brackets</string>
<string name="cancel">Cancel</string> <string name="cancel">Cancel</string>
<string name="Ok">Ok</string>
<string name="ClearClipboard">Clipboard cleared.</string> <string name="ClearClipboard">Clipboard cleared.</string>
@@ -210,7 +211,7 @@
<string name="omitbackup_title">Don\'t search backup and recycle bin entries</string> <string name="omitbackup_title">Don\'t search backup and recycle bin entries</string>
<string name="omitbackup_summary">Omit \'Backup\' and Recycle Bin group from search results</string> <string name="omitbackup_summary">Omit \'Backup\' and Recycle Bin group from search results</string>
<string name="pass_filename">KeePass database filename</string> <string name="pass_filename">KeePass database filename</string>
<string name="password_title">Enter database password</string> <string name="password_title">Enter databoase password</string>
<string name="master_key_type">Select master key type:</string> <string name="master_key_type">Select master key type:</string>
<string name="progress_create">Creating new database…</string> <string name="progress_create">Creating new database…</string>
<string name="create_database">Create database</string> <string name="create_database">Create database</string>
@@ -430,6 +431,10 @@
<string name="AskOverwriteBinary_no">Rename</string> <string name="AskOverwriteBinary_no">Rename</string>
<string name="AttachFailed">Failed to add file attachment.</string> <string name="AttachFailed">Failed to add file attachment.</string>
<string name="RecycleBin">Recycle Bin</string> <string name="RecycleBin">Recycle Bin</string>
<string name="UpdatingTemplateIds">Updating template entries </string>
<string name="AskDeletePermanentlyEntry">Do you want to delete this entry permanently? Press No to recycle.</string> <string name="AskDeletePermanentlyEntry">Do you want to delete this entry permanently? Press No to recycle.</string>
<string name="AskDeletePermanentlyGroup">Do you want to delete this group permanently? Press No to recycle.</string> <string name="AskDeletePermanentlyGroup">Do you want to delete this group permanently? Press No to recycle.</string>
<string name="AskDeletePermanentlyItems">Do you want to delete the selected elements permanently? Press No to recycle.</string> <string name="AskDeletePermanentlyItems">Do you want to delete the selected elements permanently? Press No to recycle.</string>
@@ -731,6 +736,12 @@
</string> </string>
<string name="open_other_db">Open another database…</string>
<string name="select_database">Select database</string>
<string name="ChangleLegacyTemplateIds_Title">Identical template entry ids</string>
<string name="ChangleLegacyTemplateIds_Message">Your database contains template entries with the same UUIDs as template entries in another open database. In order to use both databases simultaneously, Keepass2Android will modify the IDs of the database you are about to open.</string>
<string name="DbUnlockedChannel_name">Database unlocked</string> <string name="DbUnlockedChannel_name">Database unlocked</string>
<string name="DbUnlockedChannel_desc">Notification about the database being unlocked</string> <string name="DbUnlockedChannel_desc">Notification about the database being unlocked</string>

View File

@@ -6,25 +6,155 @@ using System.Text;
using Android.App; using Android.App;
using Android.Content; using Android.Content;
using Android.Content.PM; using Android.Content.PM;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.OS; using Android.OS;
using Android.Preferences; using Android.Preferences;
using Android.Runtime; using Android.Runtime;
using Android.Support.V7.App;
using Android.Text;
using Android.Util;
using Android.Views; using Android.Views;
using Android.Widget; using Android.Widget;
using keepass2android.Io; using keepass2android.Io;
using keepass2android.Utils; using keepass2android.Utils;
using KeeChallenge;
using KeePassLib.Keys; using KeePassLib.Keys;
using KeePassLib.Serialization; using KeePassLib.Serialization;
using Object = Java.Lang.Object;
namespace keepass2android namespace keepass2android
{ {
[Activity(Label = AppNames.AppName, MainLauncher = false, Theme = "@style/MyTheme_Blue", LaunchMode = LaunchMode.SingleInstance)] [Activity(Label = AppNames.AppName, MainLauncher = false, Theme = "@style/MyTheme_Blue", LaunchMode = LaunchMode.SingleInstance)]
public class SelectCurrentDbActivity : Activity public class SelectCurrentDbActivity : AppCompatActivity
{ {
public class OpenDatabaseAdapter : BaseAdapter
{
private readonly SelectCurrentDbActivity _context;
internal List<Database> _displayedDatabases;
public OpenDatabaseAdapter(SelectCurrentDbActivity context)
{
_context = context;
Update();
}
public override Object GetItem(int position)
{
return position;
}
public override long GetItemId(int position)
{
return position;
}
public static float convertDpToPixel(float dp, Context context)
{
return Util.convertDpToPixel(dp, context);
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
Button btn;
if (convertView == null)
{
// if it's not recycled, initialize some attributes
btn = new Button(_context);
btn.LayoutParameters = new GridView.LayoutParams((int) convertDpToPixel(140, _context),
(int) convertDpToPixel(150, _context));
btn.SetBackgroundResource(Resource.Drawable.storagetype_button_bg);
btn.SetPadding((int) convertDpToPixel(4, _context),
(int) convertDpToPixel(20, _context),
(int) convertDpToPixel(4, _context),
(int) convertDpToPixel(4, _context));
btn.SetTextSize(ComplexUnitType.Sp, 11);
btn.SetTextColor(new Color(115, 115, 115));
btn.SetSingleLine(false);
btn.Gravity = GravityFlags.Center;
btn.Click += (sender, args) =>
{
int pos;
int.TryParse(((Button) sender).Tag.ToString(), out pos);
if (pos < _displayedDatabases.Count)
_context.OnItemSelected(_displayedDatabases[pos]);
else
{
_context.OnOpenOther();
}
};
}
else
{
btn = (Button) convertView;
}
btn.Tag = position.ToString();
string displayName;
Drawable drawable;
if (position < _displayedDatabases.Count)
{
var db = _displayedDatabases[position];
drawable = App.Kp2a.GetResourceDrawable("ic_storage_" + Util.GetProtocolId(db.Ioc));
displayName = db.KpDatabase.Name;
displayName += "\n" + App.Kp2a.GetFileStorage(db.Ioc).GetDisplayName(db.Ioc);
}
else
{
displayName = _context.GetString(Resource.String.start_open_file);
drawable = App.Kp2a.GetResourceDrawable("ic_nav_changedb");
}
var str = new SpannableString(displayName);
btn.TextFormatted = str;
//var drawable = ContextCompat.GetDrawable(context, Resource.Drawable.Icon);
btn.SetCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null);
return btn;
}
public override int Count
{
get { return _displayedDatabases.Count+1; }
}
public void Update()
{
_displayedDatabases = App.Kp2a.OpenDatabases.ToList();
}
}
private void OnOpenOther()
{
StartFileSelect();
}
private void OnItemSelected(Database selectedDatabase)
{
App.Kp2a.CurrentDb = selectedDatabase;
AppTask.LaunchFirstGroupActivity(this);
}
protected override void OnCreate(Bundle savedInstanceState) protected override void OnCreate(Bundle savedInstanceState)
{ {
base.OnCreate(savedInstanceState); base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.open_db_selection);
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar);
SetSupportActionBar(toolbar);
SupportActionBar.Title = GetString(Resource.String.select_database);
if ((AppTask == null) && (Intent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory))) if ((AppTask == null) && (Intent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory)))
{ {
AppTask = new NullTask(); AppTask = new NullTask();
@@ -33,6 +163,12 @@ namespace keepass2android
{ {
AppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent); AppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
} }
_adapter = new OpenDatabaseAdapter(this);
var gridView = FindViewById<GridView>(Resource.Id.gridview);
gridView.ItemClick += (sender, args) => OnItemSelected(_adapter._displayedDatabases[args.Position]);
gridView.Adapter = _adapter;
} }
@@ -44,54 +180,78 @@ namespace keepass2android
protected override void OnResume() protected override void OnResume()
{ {
base.OnResume(); base.OnResume();
if (!IsFinishing) if (!IsFinishing && !LaunchingPasswordActivity)
{ {
if (App.Kp2a.GetDb() == null) if (App.Kp2a.OpenDatabases.Any() == false)
{ {
// Load default database StartFileSelect();
ISharedPreferences prefs = Android.Preferences.PreferenceManager.GetDefaultSharedPreferences(this);
String defaultFileName = prefs.GetString(PasswordActivity.KeyDefaultFilename, "");
if (defaultFileName.Length > 0)
{
try
{
PasswordActivity.Launch(this, LoadIoc(defaultFileName), AppTask);
return;
}
catch (Exception e)
{
Toast.MakeText(this, e.Message, ToastLength.Long);
// Ignore exception
}
}
Intent intent = new Intent(this, typeof(FileSelectActivity));
AppTask.ToIntent(intent);
intent.AddFlags(ActivityFlags.ForwardResult);
StartActivity(intent);
return; return;
} }
if (_loadAnotherDatabase)
{
StartFileSelect();
_loadAnotherDatabase = false;
return;
}
//database loaded //database loaded
if (App.Kp2a.QuickLocked) if (App.Kp2a.QuickLocked)
{ {
var i = new Intent(this, typeof(QuickUnlock)); var i = new Intent(this, typeof(QuickUnlock));
Util.PutIoConnectionToIntent(App.Kp2a.GetDb().Ioc, i); Util.PutIoConnectionToIntent(App.Kp2a.GetDbForQuickUnlock().Ioc, i);
Kp2aLog.Log("Starting QuickUnlock"); Kp2aLog.Log("Starting QuickUnlock");
StartActivityForResult(i, 0); StartActivityForResult(i, 0);
return;
} }
else
//database(s) unlocked
if (App.Kp2a.OpenDatabases.Count() == 1)
{ {
AppTask.LaunchFirstGroupActivity(this); AppTask.LaunchFirstGroupActivity(this);
return;
} }
//more than one database open or user requested to load another db. Don't launch another activity.
_adapter.Update();
_adapter.NotifyDataSetChanged();
} }
base.OnResume(); base.OnResume();
} }
protected override void OnPause()
{
LaunchingPasswordActivity = false;
base.OnPause();
}
private void StartFileSelect()
{
Intent intent = new Intent(this, typeof(FileSelectActivity));
AppTask.ToIntent(intent);
intent.AddFlags(ActivityFlags.ForwardResult);
StartActivity(intent);
}
internal AppTask AppTask; internal AppTask AppTask;
private bool _loadAnotherDatabase;
private OpenDatabaseAdapter _adapter;
public override void OnBackPressed()
{
base.OnBackPressed();
if (PreferenceManager.GetDefaultSharedPreferences(this)
.GetBoolean(GetString(Resource.String.LockWhenNavigateBack_key), false))
{
App.Kp2a.Lock();
}
//by leaving the app with the back button, the user probably wants to cancel the task
//The activity might be resumed (through Android's recent tasks list), then use a NullTask:
AppTask = new NullTask();
Finish();
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{ {
@@ -104,15 +264,10 @@ namespace keepass2android
switch (resultCode) switch (resultCode)
{ {
case KeePass.ExitNormal: // Returned to this screen using the Back key case KeePass.ExitNormal: // Returned to this screen using the Back key
if (PreferenceManager.GetDefaultSharedPreferences(this) if (App.Kp2a.OpenDatabases.Count() == 1)
.GetBoolean(GetString(Resource.String.LockWhenNavigateBack_key), false))
{ {
App.Kp2a.LockDatabase(); OnBackPressed();
} }
//by leaving the app with the back button, the user probably wants to cancel the task
//The activity might be resumed (through Android's recent tasks list), then use a NullTask:
AppTask = new NullTask();
Finish();
break; break;
case KeePass.ExitLock: case KeePass.ExitLock:
// The database has already been locked, and the quick unlock screen will be shown if appropriate // The database has already been locked, and the quick unlock screen will be shown if appropriate
@@ -128,18 +283,21 @@ namespace keepass2android
break; break;
case KeePass.ExitReloadDb: case KeePass.ExitReloadDb:
if (App.Kp2a.GetDb() != null) if (App.Kp2a.CurrentDb!= null)
{ {
//remember the composite key for reloading: //remember the composite key for reloading:
var compositeKey = App.Kp2a.GetDb().KpDatabase.MasterKey; var compositeKey = App.Kp2a.CurrentDb.KpDatabase.MasterKey;
var ioc = App.Kp2a.GetDb().Ioc; var ioc = App.Kp2a.CurrentDb.Ioc;
//lock the database: //lock the database:
App.Kp2a.LockDatabase(false); App.Kp2a.CloseDatabase(App.Kp2a.CurrentDb);
LaunchPasswordActivityForReload(ioc, compositeKey); LaunchPasswordActivityForReload(ioc, compositeKey);
} }
break;
case KeePass.ExitLoadAnotherDb:
_loadAnotherDatabase = true;
break; break;
} }
@@ -147,7 +305,10 @@ namespace keepass2android
private void LaunchPasswordActivityForReload(IOConnectionInfo ioc, CompositeKey compositeKey) private void LaunchPasswordActivityForReload(IOConnectionInfo ioc, CompositeKey compositeKey)
{ {
LaunchingPasswordActivity = true;
PasswordActivity.Launch(this, ioc, AppTask, compositeKey); PasswordActivity.Launch(this, ioc, AppTask, compositeKey);
} }
public bool LaunchingPasswordActivity { get; set; }
} }
} }

View File

@@ -104,13 +104,13 @@ namespace keepass2android
_finish.Filename = _dlg.Keyfile; _finish.Filename = _dlg.Keyfile;
} }
FingerprintUnlockMode um; FingerprintUnlockMode um;
Enum.TryParse(PreferenceManager.GetDefaultSharedPreferences(_dlg.Context).GetString(App.Kp2a.GetDb().CurrentFingerprintModePrefKey, ""), out um); Enum.TryParse(PreferenceManager.GetDefaultSharedPreferences(_dlg.Context).GetString(App.Kp2a.CurrentDb.CurrentFingerprintModePrefKey, ""), out um);
if (um == FingerprintUnlockMode.FullUnlock) if (um == FingerprintUnlockMode.FullUnlock)
{ {
ISharedPreferencesEditor edit = PreferenceManager.GetDefaultSharedPreferences(_dlg.Context).Edit(); ISharedPreferencesEditor edit = PreferenceManager.GetDefaultSharedPreferences(_dlg.Context).Edit();
edit.PutString(App.Kp2a.GetDb().CurrentFingerprintPrefKey, ""); edit.PutString(App.Kp2a.CurrentDb.CurrentFingerprintPrefKey, "");
edit.PutString(App.Kp2a.GetDb().CurrentFingerprintModePrefKey, FingerprintUnlockMode.Disabled.ToString()); edit.PutString(App.Kp2a.CurrentDb.CurrentFingerprintModePrefKey, FingerprintUnlockMode.Disabled.ToString());
edit.Commit(); edit.Commit();
Toast.MakeText(_dlg.Context, Resource.String.fingerprint_reenable, ToastLength.Long).Show(); Toast.MakeText(_dlg.Context, Resource.String.fingerprint_reenable, ToastLength.Long).Show();

View File

@@ -26,6 +26,7 @@ using Android.Views;
using Android.Widget; using Android.Widget;
using Android.Content.PM; using Android.Content.PM;
using Android.Preferences; using Android.Preferences;
using KeePassLib;
using KeePassLib.Utility; using KeePassLib.Utility;
namespace keepass2android namespace keepass2android
@@ -63,9 +64,6 @@ namespace keepass2android
} }
private Database _db;
public override bool IsSearchResult public override bool IsSearchResult
{ {
get { return true; } get { return true; }
@@ -78,8 +76,6 @@ namespace keepass2android
//if user presses back to leave this activity: //if user presses back to leave this activity:
SetResult(Result.Canceled); SetResult(Result.Canceled);
_db = App.Kp2a.GetDb();
UpdateBottomBarElementVisibility(Resource.Id.select_other_entry, true); UpdateBottomBarElementVisibility(Resource.Id.select_other_entry, true);
UpdateBottomBarElementVisibility(Resource.Id.add_url_entry, true); UpdateBottomBarElementVisibility(Resource.Id.add_url_entry, true);
@@ -107,24 +103,41 @@ namespace keepass2android
{ {
try try
{ {
//first: search for exact url foreach (var db in App.Kp2a.OpenDatabases)
Group = _db.SearchForExactUrl(url); {
if (!url.StartsWith("androidapp://")) PwGroup resultsForThisDb;
{ //first: search for exact url
//if no results, search for host (e.g. "accounts.google.com") resultsForThisDb = db.SearchForExactUrl(url);
if (!Group.Entries.Any()) if (!url.StartsWith("androidapp://"))
Group = _db.SearchForHost(url, false); {
//if still no results, search for host, allowing subdomains ("www.google.com" in entry is ok for "accounts.google.com" in search (but not the other way around) //if no results, search for host (e.g. "accounts.google.com")
if (!Group.Entries.Any()) if (!resultsForThisDb.Entries.Any())
Group = _db.SearchForHost(url, true); resultsForThisDb = db.SearchForHost(url, false);
//if still no results, search for host, allowing subdomains ("www.google.com" in entry is ok for "accounts.google.com" in search (but not the other way around)
if (!resultsForThisDb.Entries.Any())
resultsForThisDb = db.SearchForHost(url, true);
} }
//if no results returned up to now, try to search through other fields as well: //if no results returned up to now, try to search through other fields as well:
if (!Group.Entries.Any()) if (!resultsForThisDb.Entries.Any())
Group = _db.SearchForText(url); resultsForThisDb = db.SearchForText(url);
//search for host as text //search for host as text
if (!Group.Entries.Any()) if (!resultsForThisDb.Entries.Any())
Group = _db.SearchForText(UrlUtil.GetHost(url.Trim())); resultsForThisDb = db.SearchForText(UrlUtil.GetHost(url.Trim()));
if (Group == null)
{
Group = resultsForThisDb;
}
else
{
foreach (var entry in resultsForThisDb.Entries)
{
Group.AddEntry(entry, false,false);
}
}
}
} catch (Exception e) } catch (Exception e)
{ {
@@ -164,7 +177,7 @@ namespace keepass2android
View createUrlEntry = FindViewById (Resource.Id.add_url_entry); View createUrlEntry = FindViewById (Resource.Id.add_url_entry);
if (App.Kp2a.GetDb().CanWrite) if (App.Kp2a.OpenDatabases.Any(db => db.CanWrite))
{ {
createUrlEntry.Visibility = ViewStates.Visible; createUrlEntry.Visibility = ViewStates.Visible;
createUrlEntry.Click += (sender, e) => createUrlEntry.Click += (sender, e) =>
@@ -194,5 +207,10 @@ namespace keepass2android
{ {
get { return Resource.Layout.searchurlresults; } get { return Resource.Layout.searchurlresults; }
} }
public override bool EntriesBelongToCurrentDatabaseOnly
{
get { return false; }
}
}} }}

View File

@@ -13,10 +13,12 @@ namespace keepass2android
readonly ITotpPluginAdapter[] _pluginAdapters = new ITotpPluginAdapter[] { new TrayTotpPluginAdapter(), new KeeOtpPluginAdapter(), new KeeWebOtpPluginAdapter() }; readonly ITotpPluginAdapter[] _pluginAdapters = new ITotpPluginAdapter[] { new TrayTotpPluginAdapter(), new KeeOtpPluginAdapter(), new KeeWebOtpPluginAdapter() };
public void OnOpenEntry() public void OnOpenEntry()
{ {
foreach (ITotpPluginAdapter adapter in _pluginAdapters) if (App.Kp2a.LastOpenedEntry == null)
return;
foreach (ITotpPluginAdapter adapter in _pluginAdapters)
{ {
TotpData totpData = adapter.GetTotpData(App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString()), Application.Context, false); TotpData totpData = adapter.GetTotpData(App.Kp2a.LastOpenedEntry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString()), Application.Context, false);
if (totpData.IsTotpEnry) if (totpData.IsTotpEnry)
{ {
new UpdateTotpTimerTask(Application.Context, adapter).Run(); new UpdateTotpTimerTask(Application.Context, adapter).Run();

View File

@@ -27,10 +27,10 @@ namespace PluginTOTP
{ {
try try
{ {
if (App.Kp2a.GetDb().LastOpenedEntry == null) if (App.Kp2a.LastOpenedEntry == null)
return; //DB was locked return; //DB was locked
Dictionary<string, string> entryFields = App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString()); Dictionary<string, string> entryFields = App.Kp2a.LastOpenedEntry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString());
//mute warnings to avoid repeated display of the toasts //mute warnings to avoid repeated display of the toasts
TotpData totpData = _adapter.GetTotpData(entryFields, _context, true /*mute warnings*/); TotpData totpData = _adapter.GetTotpData(entryFields, _context, true /*mute warnings*/);
if (totpData.IsTotpEnry) if (totpData.IsTotpEnry)
@@ -58,10 +58,10 @@ namespace PluginTOTP
private void UpdateEntryData(string totp) private void UpdateEntryData(string totp)
{ {
//update the Entry output in the App database and notify the CopyToClipboard service //update the Entry output in the App database and notify the CopyToClipboard service
App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.Set(_totp, new ProtectedString(true, totp)); App.Kp2a.LastOpenedEntry.OutputStrings.Set(_totp, new ProtectedString(true, totp));
Intent updateKeyboardIntent = new Intent(_context, typeof(CopyToClipboardService)); Intent updateKeyboardIntent = new Intent(_context, typeof(CopyToClipboardService));
updateKeyboardIntent.SetAction(Intents.UpdateKeyboard); updateKeyboardIntent.SetAction(Intents.UpdateKeyboard);
updateKeyboardIntent.PutExtra("entry", App.Kp2a.GetDb().LastOpenedEntry.Uuid.ToHexString()); updateKeyboardIntent.PutExtra("entry", App.Kp2a.LastOpenedEntry.Uuid.ToHexString());
_context.StartService(updateKeyboardIntent); _context.StartService(updateKeyboardIntent);
} }
@@ -73,7 +73,7 @@ namespace PluginTOTP
i.SetPackage(_context.PackageName); i.SetPackage(_context.PackageName);
i.PutExtra(Strings.ExtraSender, _context.PackageName); i.PutExtra(Strings.ExtraSender, _context.PackageName);
i.PutExtra(Strings.ExtraFieldValue, totp); i.PutExtra(Strings.ExtraFieldValue, totp);
i.PutExtra(Strings.ExtraEntryId, App.Kp2a.GetDb().LastOpenedEntry.Entry.Uuid.ToHexString()); i.PutExtra(Strings.ExtraEntryId, App.Kp2a.LastOpenedEntry.Entry.Uuid.ToHexString());
i.PutExtra(Strings.ExtraFieldId, _totp); i.PutExtra(Strings.ExtraFieldId, _totp);
i.PutExtra(Strings.ExtraFieldProtected, true); i.PutExtra(Strings.ExtraFieldProtected, true);

View File

@@ -46,20 +46,20 @@ namespace keepass2android
public const String KeyServercredmode = "serverCredRememberMode"; public const String KeyServercredmode = "serverCredRememberMode";
public static void PutIoConnectionToIntent(IOConnectionInfo ioc, Intent i) public static void PutIoConnectionToIntent(IOConnectionInfo ioc, Intent i, string prefix="")
{ {
i.PutExtra(KeyFilename, ioc.Path); i.PutExtra(prefix+KeyFilename, ioc.Path);
i.PutExtra(KeyServerusername, ioc.UserName); i.PutExtra(prefix + KeyServerusername, ioc.UserName);
i.PutExtra(KeyServerpassword, ioc.Password); i.PutExtra(prefix + KeyServerpassword, ioc.Password);
i.PutExtra(KeyServercredmode, (int)ioc.CredSaveMode); i.PutExtra(prefix + KeyServercredmode, (int)ioc.CredSaveMode);
} }
public static void SetIoConnectionFromIntent(IOConnectionInfo ioc, Intent i) public static void SetIoConnectionFromIntent(IOConnectionInfo ioc, Intent i, string prefix="")
{ {
ioc.Path = i.GetStringExtra(KeyFilename); ioc.Path = i.GetStringExtra(prefix + KeyFilename);
ioc.UserName = i.GetStringExtra(KeyServerusername) ?? ""; ioc.UserName = i.GetStringExtra(prefix + KeyServerusername) ?? "";
ioc.Password = i.GetStringExtra(KeyServerpassword) ?? ""; ioc.Password = i.GetStringExtra(prefix + KeyServerpassword) ?? "";
ioc.CredSaveMode = (IOCredSaveMode)i.GetIntExtra(KeyServercredmode, (int)IOCredSaveMode.NoSave); ioc.CredSaveMode = (IOCredSaveMode)i.GetIntExtra(prefix + KeyServercredmode, (int)IOCredSaveMode.NoSave);
} }
public static Bitmap DrawableToBitmap(Drawable drawable) public static Bitmap DrawableToBitmap(Drawable drawable)
@@ -558,6 +558,15 @@ namespace keepass2android
int width = (int)(0.9 * context.Resources.GetDimension(Android.Resource.Dimension.NotificationLargeIconWidth)); int width = (int)(0.9 * context.Resources.GetDimension(Android.Resource.Dimension.NotificationLargeIconWidth));
return Bitmap.CreateScaledBitmap(unscaled, width, height, true); return Bitmap.CreateScaledBitmap(unscaled, width, height, true);
} }
public static string GetProtocolId(IOConnectionInfo ioc)
{
string displayPath = App.Kp2a.GetFileStorage(ioc).GetDisplayName(ioc);
int protocolSeparatorPos = displayPath.IndexOf("://", StringComparison.Ordinal);
string protocolId = protocolSeparatorPos < 0 ?
"file" : displayPath.Substring(0, protocolSeparatorPos);
return protocolId;
}
} }
} }

View File

@@ -18,6 +18,7 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Net.Security; using System.Net.Security;
using Android.App; using Android.App;
using Android.Content; using Android.Content;
@@ -40,6 +41,7 @@ using TwofishCipher;
using Keepass2android.Pluginsdk; using Keepass2android.Pluginsdk;
using keepass2android.Io; using keepass2android.Io;
using keepass2android.addons.OtpKeyProv; using keepass2android.addons.OtpKeyProv;
using keepass2android.database.edit;
using KeePassLib.Interfaces; using KeePassLib.Interfaces;
using KeePassLib.Utility; using KeePassLib.Utility;
#if !NoNet #if !NoNet
@@ -100,19 +102,19 @@ namespace keepass2android
/// </summary> /// </summary>
public class Kp2aApp: IKp2aApp, ICacheSupervisor public class Kp2aApp: IKp2aApp, ICacheSupervisor
{ {
public void LockDatabase(bool allowQuickUnlock = true) public void Lock(bool allowQuickUnlock = true)
{ {
if (GetDb() != null) if (OpenDatabases.Any())
{ {
if (QuickUnlockEnabled && allowQuickUnlock && if (QuickUnlockEnabled && allowQuickUnlock &&
GetDb().KpDatabase.MasterKey.ContainsType(typeof(KcpPassword)) && GetDbForQuickUnlock().KpDatabase.MasterKey.ContainsType(typeof(KcpPassword)) &&
!((KcpPassword)App.Kp2a.GetDb().KpDatabase.MasterKey.GetUserKey(typeof(KcpPassword))).Password.IsEmpty) !((KcpPassword)App.Kp2a.GetDbForQuickUnlock().KpDatabase.MasterKey.GetUserKey(typeof(KcpPassword))).Password.IsEmpty)
{ {
if (!QuickLocked) if (!QuickLocked)
{ {
Kp2aLog.Log("QuickLocking database"); Kp2aLog.Log("QuickLocking database");
QuickLocked = true; QuickLocked = true;
GetDb().LastOpenedEntry = null; LastOpenedEntry = null;
BroadcastDatabaseAction(Application.Context, Strings.ActionLockDatabase); BroadcastDatabaseAction(Application.Context, Strings.ActionLockDatabase);
} }
else else
@@ -126,8 +128,10 @@ namespace keepass2android
BroadcastDatabaseAction(Application.Context, Strings.ActionCloseDatabase); BroadcastDatabaseAction(Application.Context, Strings.ActionCloseDatabase);
// Couldn't quick-lock, so unload database instead // Couldn't quick-lock, so unload database(s) instead
_db = null; _openDatabases.Clear();
_currentDatabase = null;
LastOpenedEntry = null;
QuickLocked = false; QuickLocked = false;
} }
} }
@@ -143,28 +147,24 @@ namespace keepass2android
public void BroadcastDatabaseAction(Context ctx, string action) public void BroadcastDatabaseAction(Context ctx, string action)
{ {
Intent i = new Intent(action); foreach (Database db in OpenDatabases)
{
Intent i = new Intent(action);
//seems like this can happen. This code is for debugging. i.PutExtra(Strings.ExtraDatabaseFileDisplayname, GetFileStorage(db.Ioc).GetDisplayName(db.Ioc));
if (App.Kp2a.GetDb().Ioc == null) i.PutExtra(Strings.ExtraDatabaseFilepath, db.Ioc.Path);
{ foreach (var plugin in new PluginDatabase(ctx).GetPluginsWithAcceptedScope(Strings.ScopeDatabaseActions))
Kp2aLog.LogUnexpectedError(new Exception("App.Kp2a.GetDb().Ioc is null")); {
return; i.SetPackage(plugin);
} ctx.SendBroadcast(i);
}
}
i.PutExtra(Strings.ExtraDatabaseFileDisplayname, App.Kp2a.GetFileStorage(App.Kp2a.GetDb().Ioc).GetDisplayName(App.Kp2a.GetDb().Ioc));
i.PutExtra(Strings.ExtraDatabaseFilepath, App.Kp2a.GetDb().Ioc.Path);
foreach (var plugin in new PluginDatabase(ctx).GetPluginsWithAcceptedScope(Strings.ScopeDatabaseActions))
{
i.SetPackage(plugin);
ctx.SendBroadcast(i);
}
} }
public void LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compositeKey, public Database LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compositeKey, ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat)
ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat)
{ {
var prefs = PreferenceManager.GetDefaultSharedPreferences(Application.Context); var prefs = PreferenceManager.GetDefaultSharedPreferences(Application.Context);
var createBackup = prefs.GetBoolean(Application.Context.GetString(Resource.String.CreateBackups_key), true) var createBackup = prefs.GetBoolean(Application.Context.GetString(Resource.String.CreateBackups_key), true)
@@ -180,10 +180,27 @@ namespace keepass2android
memoryStream.Seek(0, SeekOrigin.Begin); memoryStream.Seek(0, SeekOrigin.Begin);
} }
_db = CreateNewDatabase(); foreach (Database openDb in _openDatabases)
_db.LoadData(this, ioConnectionInfo, memoryStream, compositeKey, statusLogger, databaseFormat); {
if (openDb.Ioc.IsSameFileAs(ioConnectionInfo))
{
//TODO check this earlier and simply open the database's root group
throw new Exception("Database already loaded!");
}
if (createBackup) }
var newDb = new Database(new DrawableFactory(), this);
newDb.LoadData(this, ioConnectionInfo, memoryStream, compositeKey, statusLogger, databaseFormat);
_currentDatabase = newDb;
_openDatabases.Add(newDb);
if (createBackup)
{ {
statusLogger.UpdateMessage(Application.Context.GetString(Resource.String.UpdatingBackup)); statusLogger.UpdateMessage(Application.Context.GetString(Resource.String.UpdatingBackup));
Java.IO.File internalDirectory = IoUtil.GetInternalDirectory(Application.Context); Java.IO.File internalDirectory = IoUtil.GetInternalDirectory(Application.Context);
@@ -201,9 +218,12 @@ namespace keepass2android
using (var transaction = new LocalFileStorage(App.Kp2a).OpenWriteTransaction(targetIoc, false)) using (var transaction = new LocalFileStorage(App.Kp2a).OpenWriteTransaction(targetIoc, false))
{ {
var file = transaction.OpenFile(); using (var file = transaction.OpenFile())
backupCopy.CopyTo(file); {
transaction.CommitWrite(); backupCopy.CopyTo(file);
transaction.CommitWrite();
}
} }
Java.Lang.Object baseIocDisplayName = baseDisplayName; Java.Lang.Object baseIocDisplayName = baseDisplayName;
@@ -226,9 +246,53 @@ namespace keepass2android
} }
UpdateOngoingNotification(); UpdateOngoingNotification();
}
internal void UnlockDatabase() return newDb;
}
public Database FindDatabaseForEntryId(PwUuid entryKey)
{
foreach (Database db in OpenDatabases)
{
if (db.Entries.ContainsKey(entryKey))
return db;
}
return null;
}
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.Entries.ContainsKey(LastOpenedEntry.Uuid))
{
LastOpenedEntry = null;
}
_openDatabases.Remove(db);
if (_currentDatabase == db)
_currentDatabase = _openDatabases.First();
UpdateOngoingNotification();
//TODO broadcast event so affected activities can close/update?
}
public Database FindDatabaseForGroupId(PwUuid groupKey)
{
foreach (Database db in OpenDatabases)
{
if (db.Groups.ContainsKey(groupKey))
return db;
}
return null;
}
internal void UnlockDatabase()
{ {
QuickLocked = false; QuickLocked = false;
@@ -258,7 +322,7 @@ namespace keepass2android
public bool DatabaseIsUnlocked public bool DatabaseIsUnlocked
{ {
get { return GetDb() != null && !QuickLocked; } get { return OpenDatabases.Any() && !QuickLocked; }
} }
#region QuickUnlock #region QuickUnlock
@@ -287,8 +351,6 @@ namespace keepass2android
#endregion #endregion
private Database _db;
/// <summary> /// <summary>
/// See comments to EntryEditActivityState. /// See comments to EntryEditActivityState.
/// </summary> /// </summary>
@@ -297,10 +359,50 @@ namespace keepass2android
public FileDbHelper FileDbHelper; public FileDbHelper FileDbHelper;
private List<IFileStorage> _fileStorages; private List<IFileStorage> _fileStorages;
public Database GetDb() private readonly List<Database> _openDatabases = new List<Database>();
{ private Database _currentDatabase;
return _db;
} public IEnumerable<Database> OpenDatabases
{
get { return _openDatabases; }
}
public readonly HashSet<PwGroup> dirty = new HashSet<PwGroup>(new PwGroupEqualityFromIdComparer());
public HashSet<PwGroup> DirtyGroups { get { return dirty; } }
public void MarkAllGroupsAsDirty()
{
foreach (var db in OpenDatabases)
foreach (PwGroup group in db.Groups.Values)
{
DirtyGroups.Add(group);
}
}
/// <summary>
/// Information about the last opened entry. Includes the entry but also transformed fields.
/// </summary>
public PwEntryOutput LastOpenedEntry { get; set; }
public Database CurrentDb
{
get { return _currentDatabase; }
set
{
if (!OpenDatabases.Contains(value))
throw new Exception("Cannot set database as current. Not in list of opened databases!");
_currentDatabase = value;
}
}
public Database GetDbForQuickUnlock()
{
return OpenDatabases.FirstOrDefault();
}
@@ -325,19 +427,28 @@ namespace keepass2android
public void CheckForOpenFileChanged(Activity activity) public void CheckForOpenFileChanged(Activity activity)
{ {
if (GetDb()?.DidOpenFileChange() == true) if (CurrentDb?.DidOpenFileChange() == true)
{ {
if (GetDb().ReloadRequested) if (CurrentDb.ReloadRequested)
{ {
LockDatabase(false);
activity.SetResult(KeePass.ExitReloadDb); activity.SetResult(KeePass.ExitReloadDb);
activity.Finish(); activity.Finish();
} }
AskForReload(activity); else
{
AskForReload(activity);
}
} }
} }
private void AskForReload(Activity activity) public void LockSingleDatabase(Database databaseToLock, bool allowQuickUnlock)
{
//TODO implement
throw new Exception("lock single is not implemented");
}
private void AskForReload(Activity activity)
{ {
AlertDialog.Builder builder = new AlertDialog.Builder(activity); AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.SetTitle(activity.GetString(Resource.String.AskReloadFile_title)); builder.SetTitle(activity.GetString(Resource.String.AskReloadFile_title));
@@ -347,7 +458,7 @@ namespace keepass2android
builder.SetPositiveButton(activity.GetString(Android.Resource.String.Yes), builder.SetPositiveButton(activity.GetString(Android.Resource.String.Yes),
(dlgSender, dlgEvt) => (dlgSender, dlgEvt) =>
{ {
GetDb().ReloadRequested = true; CurrentDb.ReloadRequested = true;
activity.SetResult(KeePass.ExitReloadDb); activity.SetResult(KeePass.ExitReloadDb);
activity.Finish(); activity.Finish();
@@ -724,7 +835,8 @@ namespace keepass2android
internal void OnTerminate() internal void OnTerminate()
{ {
_db = null; _openDatabases.Clear();
_currentDatabase = null;
if (FileDbHelper != null && FileDbHelper.IsOpen()) if (FileDbHelper != null && FileDbHelper.IsOpen())
{ {
@@ -752,8 +864,9 @@ namespace keepass2android
public Database CreateNewDatabase() public Database CreateNewDatabase()
{ {
_db = new Database(new DrawableFactory(), this); _currentDatabase = new Database(new DrawableFactory(), this);
return _db; _openDatabases.Add(_currentDatabase);
return _currentDatabase;
} }
internal void ShowToast(string message) internal void ShowToast(string message)
@@ -893,10 +1006,45 @@ namespace keepass2android
Application.Context.GetString(Resource.String.LockWhenScreenOff_key), Application.Context.GetString(Resource.String.LockWhenScreenOff_key),
false)) false))
{ {
App.Kp2a.LockDatabase(); App.Kp2a.Lock();
} }
} }
}
public Database GetDatabase(IOConnectionInfo dbIoc)
{
foreach (Database db in OpenDatabases)
{
if (db.Ioc.IsSameFileAs(dbIoc))
return db;
}
throw new Exception("Database not found for dbIoc!");
}
public PwGroup FindGroup(PwUuid uuid)
{
PwGroup result;
foreach (Database db in OpenDatabases)
{
if (db.Groups.TryGetValue(uuid, out result))
return result;
}
return null;
}
public IStructureItem FindStructureItem(PwUuid uuid)
{
foreach (Database db in OpenDatabases)
{
PwGroup resultGroup;
if (db.Groups.TryGetValue(uuid, out resultGroup))
return resultGroup;
PwEntry resultEntry;
if (db.Entries.TryGetValue(uuid, out resultEntry))
return resultEntry;
}
return null;
}
}
///Application class for Keepass2Android: Contains static Database variable to be used by all components. ///Application class for Keepass2Android: Contains static Database variable to be used by all components.

View File

@@ -344,7 +344,7 @@ namespace keepass2android
activity.StartNotificationsService(false); activity.StartNotificationsService(false);
} }
virtual public void PopulatePasswordAccessServiceIntent(Intent intent) public virtual void PopulatePasswordAccessServiceIntent(Intent intent)
{ {
} }
@@ -434,7 +434,8 @@ namespace keepass2android
public override void CompleteOnCreateEntryActivity(EntryActivity activity) public override void CompleteOnCreateEntryActivity(EntryActivity activity)
{ {
App.Kp2a.GetDb().LastOpenedEntry.SearchUrl = UrlToSearchFor; if (App.Kp2a.LastOpenedEntry != null)
App.Kp2a.LastOpenedEntry.SearchUrl = UrlToSearchFor;
base.CompleteOnCreateEntryActivity(activity); base.CompleteOnCreateEntryActivity(activity);
} }
} }
@@ -554,10 +555,11 @@ namespace keepass2android
public override void CompleteOnCreateEntryActivity(EntryActivity activity) public override void CompleteOnCreateEntryActivity(EntryActivity activity)
{ {
App.Kp2a.GetDb().LastOpenedEntry.SearchUrl = UrlToSearchFor; if (App.Kp2a.LastOpenedEntry != null)
App.Kp2a.LastOpenedEntry.SearchUrl = UrlToSearchFor;
//if the database is readonly (or no URL exists), don't offer to modify the URL //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))) if ((App.Kp2a.CurrentDb.CanWrite == false) || (String.IsNullOrEmpty(UrlToSearchFor)))
{ {
base.CompleteOnCreateEntryActivity(activity); base.CompleteOnCreateEntryActivity(activity);
return; return;
@@ -790,7 +792,8 @@ namespace keepass2android
#endif #endif
private LinkedList<string> _groupUuid; private LinkedList<string> _groupUuid;
protected AppTask TaskToBeLaunchedAfterNavigation; private readonly Database _db;
protected AppTask TaskToBeLaunchedAfterNavigation;
protected String FullGroupName { protected String FullGroupName {
get ; get ;
@@ -814,8 +817,9 @@ namespace keepass2android
/// <param name="groups">Groups.</param> /// <param name="groups">Groups.</param>
/// <param name="taskToBeLaunchedAfterNavigation">Task to be launched after navigation.</param> /// <param name="taskToBeLaunchedAfterNavigation">Task to be launched after navigation.</param>
/// <param name="toastEnable">If set to <c>true</c>, toast will be displayed after navigation.</param> /// <param name="toastEnable">If set to <c>true</c>, toast will be displayed after navigation.</param>
protected NavigateAndLaunchTask(PwGroup groups, AppTask taskToBeLaunchedAfterNavigation, bool toastEnable = false) { protected NavigateAndLaunchTask(Database db, PwGroup groups, AppTask taskToBeLaunchedAfterNavigation, bool toastEnable = false) {
TaskToBeLaunchedAfterNavigation = taskToBeLaunchedAfterNavigation; _db = db;
TaskToBeLaunchedAfterNavigation = taskToBeLaunchedAfterNavigation;
PopulateGroups (groups); PopulateGroups (groups);
ToastEnable = toastEnable; ToastEnable = toastEnable;
} }
@@ -943,7 +947,7 @@ namespace keepass2android
PwUuid nextGroupPwUuid = new PwUuid (MemUtil.HexStringToByteArray (nextGroupUuid)); PwUuid nextGroupPwUuid = new PwUuid (MemUtil.HexStringToByteArray (nextGroupUuid));
// Create Group Activity // Create Group Activity
PwGroup nextGroup = App.Kp2a.GetDb ().Groups[nextGroupPwUuid]; PwGroup nextGroup = _db.Groups[nextGroupPwUuid];
GroupActivity.Launch (groupBaseActivity, nextGroup, this); GroupActivity.Launch (groupBaseActivity, nextGroup, this);
} }
return; return;
@@ -968,12 +972,9 @@ namespace keepass2android
public class NavigateToFolder: NavigateAndLaunchTask { public class NavigateToFolder: NavigateAndLaunchTask {
public NavigateToFolder()
{
}
public NavigateToFolder(PwGroup groups, bool toastEnable = false) public NavigateToFolder(Database db, PwGroup groups, bool toastEnable = false)
: base(groups, new NullTask(), toastEnable) : base(db, groups, new NullTask(), toastEnable)
{ {
} }
@@ -981,14 +982,9 @@ namespace keepass2android
public class NavigateToFolderAndLaunchMoveElementTask: NavigateAndLaunchTask { public class NavigateToFolderAndLaunchMoveElementTask: NavigateAndLaunchTask {
public NavigateToFolderAndLaunchMoveElementTask()
{
} public NavigateToFolderAndLaunchMoveElementTask(Database db, PwGroup groups, List<PwUuid> uuids, bool toastEnable = false)
:base(db, groups, new MoveElementsTask() { Uuids = uuids }, toastEnable) {
public NavigateToFolderAndLaunchMoveElementTask(PwGroup groups, List<PwUuid> uuids, bool toastEnable = false)
:base(groups, new MoveElementsTask() { Uuids = uuids }, toastEnable) {
} }
public override void Setup(Bundle b) { public override void Setup(Bundle b) {

View File

@@ -17,10 +17,10 @@ namespace keepass2android
switch (intent.Action) switch (intent.Action)
{ {
case Intents.LockDatabase: case Intents.LockDatabase:
App.Kp2a.LockDatabase(); App.Kp2a.Lock();
break; break;
case Intents.CloseDatabase: case Intents.CloseDatabase:
App.Kp2a.LockDatabase(false /*no quick unlock*/); App.Kp2a.Lock(false /*no quick unlock*/);
break; break;
} }
} }

View File

@@ -16,6 +16,7 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/ */
using System; using System;
using System.Linq;
using Android.App; using Android.App;
using Android.Content; using Android.Content;
using Android.Database; using Android.Database;
@@ -140,7 +141,6 @@ namespace keepass2android
intent.PutExtra(SelectStorageLocationActivity.ExtraKeyWritableRequirements, (int) SelectStorageLocationActivity.WritableRequirements.WriteDesired); intent.PutExtra(SelectStorageLocationActivity.ExtraKeyWritableRequirements, (int) SelectStorageLocationActivity.WritableRequirements.WriteDesired);
intent.PutExtra(FileStorageSetupDefs.ExtraIsForSave, false); intent.PutExtra(FileStorageSetupDefs.ExtraIsForSave, false);
StartActivityForResult(intent, RequestCodeSelectIoc); StartActivityForResult(intent, RequestCodeSelectIoc);
}; };
openFileButton.Click += openFileButtonClick; openFileButton.Click += openFileButtonClick;
@@ -151,7 +151,9 @@ namespace keepass2android
//ShowFilenameDialog(false, true, true, Android.OS.Environment.ExternalStorageDirectory + GetString(Resource.String.default_file_path), "", Intents.RequestCodeFileBrowseForCreate) //ShowFilenameDialog(false, true, true, Android.OS.Environment.ExternalStorageDirectory + GetString(Resource.String.default_file_path), "", Intents.RequestCodeFileBrowseForCreate)
Intent i = new Intent(this, typeof (CreateDatabaseActivity)); Intent i = new Intent(this, typeof (CreateDatabaseActivity));
this.AppTask.ToIntent(i); this.AppTask.ToIntent(i);
StartActivityForResult(i, 0); i.SetFlags(ActivityFlags.ForwardResult);
StartActivity(i);
Finish();
}; };
createNewButton.Click += createNewButtonClick; createNewButton.Click += createNewButtonClick;
@@ -460,28 +462,22 @@ namespace keepass2android
base.OnStart(); base.OnStart();
Kp2aLog.Log("FileSelect.OnStart"); Kp2aLog.Log("FileSelect.OnStart");
var db = App.Kp2a.GetDb();
if (db != null) //if no database is loaded: load the most recent database
if ( (Intent.GetBooleanExtra(NoForwardToPasswordActivity, false)==false) && _dbHelper.HasRecentFiles() && !App.Kp2a.OpenDatabases.Any())
{ {
LaunchPasswordActivityForIoc(db.Ioc); ICursor filesCursor = _dbHelper.FetchAllFiles();
} StartManagingCursor(filesCursor);
else filesCursor.MoveToFirst();
{ IOConnectionInfo ioc = _dbHelper.CursorToIoc(filesCursor);
//if no database is loaded: load the most recent database if (App.Kp2a.GetFileStorage(ioc).RequiresSetup(ioc) == false)
if ( (Intent.GetBooleanExtra(NoForwardToPasswordActivity, false)==false) && _dbHelper.HasRecentFiles())
{ {
ICursor filesCursor = _dbHelper.FetchAllFiles(); LaunchPasswordActivityForIoc(ioc);
StartManagingCursor(filesCursor);
filesCursor.MoveToFirst();
IOConnectionInfo ioc = _dbHelper.CursorToIoc(filesCursor);
if (App.Kp2a.GetFileStorage(ioc).RequiresSetup(ioc) == false)
{
LaunchPasswordActivityForIoc(ioc);
}
} }
} }
} }
public override bool OnCreateOptionsMenu(IMenu menu) { public override bool OnCreateOptionsMenu(IMenu menu) {
base.OnCreateOptionsMenu(menu); base.OnCreateOptionsMenu(menu);

View File

@@ -1885,6 +1885,9 @@
<ItemGroup> <ItemGroup>
<AndroidResource Include="Resources\drawable-mdpi\ic_storage_nextcloud.png" /> <AndroidResource Include="Resources\drawable-mdpi\ic_storage_nextcloud.png" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\open_db_selection.xml" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" /> <Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''"> <Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">

View File

@@ -47,8 +47,9 @@ namespace keepass2android.search
private const string GetIconPathQuery = "get_icon"; private const string GetIconPathQuery = "get_icon";
private const string IconIdParameter = "IconId"; private const string IconIdParameter = "IconId";
private const string CustomIconUuidParameter = "CustomIconUuid"; private const string CustomIconUuidParameter = "CustomIconUuid";
private const string DatabaseIndexParameter = "DatabaseIndex";
private static UriMatcher UriMatcher = BuildUriMatcher(); private static UriMatcher UriMatcher = BuildUriMatcher();
static UriMatcher BuildUriMatcher() static UriMatcher BuildUriMatcher()
{ {
@@ -78,9 +79,24 @@ namespace keepass2android.search
{ {
try try
{ {
var resultsContexts = new Dictionary<PwUuid, KeyValuePair<string, string>>(); List<EntryListCursor.EntryWithContext> entriesWithContext = new List<EntryListCursor.EntryWithContext>();
var result = App.Kp2a.GetDb().Search(new SearchParameters { SearchString = searchString }, resultsContexts ); int dbIndex = 0;
return new GroupCursor(result, resultsContexts); foreach (var db in App.Kp2a.OpenDatabases)
{
var resultsContexts = new Dictionary<PwUuid, KeyValuePair<string, string>>();
PwGroup group = db.Search(new SearchParameters { SearchString = searchString }, resultsContexts);
foreach (var entry in group.Entries)
{
KeyValuePair<string, string> context;
resultsContexts.TryGetValue(entry.Uuid, out context);
entriesWithContext.Add(new EntryListCursor.EntryWithContext(entry, context, dbIndex));
}
dbIndex++;
}
return new EntryListCursor(entriesWithContext);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -116,8 +132,12 @@ namespace keepass2android.search
case UriMatches.GetIcon: case UriMatches.GetIcon:
var iconId = (PwIcon)Enum.Parse(typeof(PwIcon), uri.GetQueryParameter(IconIdParameter)); var iconId = (PwIcon)Enum.Parse(typeof(PwIcon), uri.GetQueryParameter(IconIdParameter));
var customIconUuid = new PwUuid(MemUtil.HexStringToByteArray(uri.GetQueryParameter(CustomIconUuidParameter))); var customIconUuid = new PwUuid(MemUtil.HexStringToByteArray(uri.GetQueryParameter(CustomIconUuidParameter)));
int databaseIndex = int.Parse(uri.GetQueryParameter(DatabaseIndexParameter));
List<Database> databases = App.Kp2a.OpenDatabases.ToList();
Database database = databases[databaseIndex];
var iconDrawable = App.Kp2a.GetDb().DrawableFactory.GetIconDrawable(App.Context, App.Kp2a.GetDb().KpDatabase, iconId, customIconUuid, false) as BitmapDrawable;
var iconDrawable = database.DrawableFactory.GetIconDrawable(App.Context, database.KpDatabase, iconId, customIconUuid, false) as BitmapDrawable;
if (iconDrawable?.Bitmap != null) if (iconDrawable?.Bitmap != null)
{ {
@@ -186,29 +206,41 @@ namespace keepass2android.search
#endregion #endregion
private class GroupCursor : AbstractCursor private class EntryListCursor : AbstractCursor
{ {
private static readonly string[] ColumnNames = new[] { Android.Provider.BaseColumns.Id, private readonly List<EntryWithContext> _entriesWithContexts;
private static readonly string[] ColumnNames = new[] { Android.Provider.BaseColumns.Id,
SearchManager.SuggestColumnText1, SearchManager.SuggestColumnText1,
SearchManager.SuggestColumnText2, SearchManager.SuggestColumnText2,
SearchManager.SuggestColumnIcon1, SearchManager.SuggestColumnIcon1,
SearchManager.SuggestColumnIntentDataId, SearchManager.SuggestColumnIntentDataId,
}; };
private readonly PwGroup mGroup;
private readonly IDictionary<PwUuid, KeyValuePair<string, string>> mResultContexts;
public GroupCursor(PwGroup group, IDictionary<PwUuid, KeyValuePair<string, string>> resultContexts)
public struct EntryWithContext
{
public readonly PwEntry entry;
public readonly KeyValuePair<string, string> resultContext;
public readonly int DatabaseIndex;
public EntryWithContext(PwEntry entry, KeyValuePair<string, string> mResultContext, int databaseIndex)
{
this.entry = entry;
this.resultContext = mResultContext;
DatabaseIndex = databaseIndex;
}
}
public EntryListCursor(List<EntryWithContext> entriesWithContexts)
{ {
System.Diagnostics.Debug.Assert(!group.Groups.Any(), "Expecting a flat list of groups"); _entriesWithContexts = entriesWithContexts;
mGroup = group;
mResultContexts = resultContexts;
} }
public override int Count public override int Count
{ {
get { return (int)Math.Min(mGroup.GetEntriesCount(false), int.MaxValue); } get { return _entriesWithContexts.Count; }
} }
public override string[] GetColumnNames() public override string[] GetColumnNames()
@@ -231,7 +263,10 @@ namespace keepass2android.search
{ {
get get
{ {
return mGroup.Entries.GetAt((uint)MPos); if (MPos < _entriesWithContexts.Count)
return _entriesWithContexts[MPos].entry;
return null;
} }
} }
@@ -255,12 +290,9 @@ namespace keepass2android.search
case 1: // SuggestColumnText1 case 1: // SuggestColumnText1
return CurrentEntry.Strings.ReadSafe(PwDefs.TitleField); return CurrentEntry.Strings.ReadSafe(PwDefs.TitleField);
case 2: // SuggestColumnText2 case 2: // SuggestColumnText2
KeyValuePair<string, string> context; if (MPos < _entriesWithContexts.Count)
if (mResultContexts.TryGetValue(CurrentEntry.Uuid, out context)) return Internationalise(_entriesWithContexts[MPos].resultContext);
{ return "";
return Internationalise(context);
}
return null;
case 3: // SuggestColumnIcon1 case 3: // SuggestColumnIcon1
var builder = new Android.Net.Uri.Builder(); var builder = new Android.Net.Uri.Builder();
builder.Scheme(ContentResolver.SchemeContent); builder.Scheme(ContentResolver.SchemeContent);
@@ -268,7 +300,8 @@ namespace keepass2android.search
builder.Path(GetIconPathQuery); builder.Path(GetIconPathQuery);
builder.AppendQueryParameter(IconIdParameter, CurrentEntry.IconId.ToString()); builder.AppendQueryParameter(IconIdParameter, CurrentEntry.IconId.ToString());
builder.AppendQueryParameter(CustomIconUuidParameter, CurrentEntry.CustomIconUuid.ToHexString()); builder.AppendQueryParameter(CustomIconUuidParameter, CurrentEntry.CustomIconUuid.ToHexString());
return builder.Build().ToString(); builder.AppendQueryParameter(DatabaseIndexParameter, _entriesWithContexts[MPos].DatabaseIndex.ToString());
return builder.Build().ToString();
case 4: // SuggestColumnIntentDataId case 4: // SuggestColumnIntentDataId
return CurrentEntry.Uuid.ToHexString(); return CurrentEntry.Uuid.ToHexString();
default: default:

View File

@@ -56,15 +56,10 @@ namespace keepass2android.search
ProcessIntent(Intent); ProcessIntent(Intent);
} }
protected override bool AddEntryEnabled public override bool EntriesBelongToCurrentDatabaseOnly
{ {
get { return false; } get { return false; }
} }
protected override bool AddGroupEnabled
{
get { return false; }
}
protected override void OnNewIntent(Intent intent) protected override void OnNewIntent(Intent intent)
@@ -84,7 +79,7 @@ namespace keepass2android.search
{ {
var entryIntent = new Intent(this, typeof(EntryActivity)); var entryIntent = new Intent(this, typeof(EntryActivity));
entryIntent.PutExtra(EntryActivity.KeyEntry, intent.Data.LastPathSegment); entryIntent.PutExtra(EntryActivity.KeyEntry, intent.Data.LastPathSegment);
entryIntent.AddFlags(ActivityFlags.ForwardResult); entryIntent.AddFlags(ActivityFlags.ForwardResult);
Finish(); // Close this activity so that the entry activity is navigated to from the main activity, not this one. Finish(); // Close this activity so that the entry activity is navigated to from the main activity, not this one.
StartActivity(entryIntent); StartActivity(entryIntent);
} }
@@ -97,9 +92,22 @@ namespace keepass2android.search
private void Query (SearchParameters searchParams) private void Query (SearchParameters searchParams)
{ {
try { Group = null;
Group = App.Kp2a.GetDb().Search (searchParams, null); try {
} catch (Exception e) { foreach (var db in App.Kp2a.OpenDatabases)
{
PwGroup resultsForThisDb = db.Search(searchParams, null);
if (Group == null)
Group = resultsForThisDb;
else
{
foreach (var entry in resultsForThisDb.Entries)
{
Group.AddEntry(entry, false);
}
}
}
} catch (Exception e) {
Kp2aLog.LogUnexpectedError(e); Kp2aLog.LogUnexpectedError(e);
Toast.MakeText(this,e.Message, ToastLength.Long).Show(); Toast.MakeText(this,e.Message, ToastLength.Long).Show();
Finish(); Finish();

View File

@@ -35,6 +35,7 @@ using KeePassLib;
using KeePassLib.Utility; using KeePassLib.Utility;
using Android.Views.InputMethods; using Android.Views.InputMethods;
using KeePass.Util.Spr; using KeePass.Util.Spr;
using KeePassLib.Serialization;
namespace keepass2android namespace keepass2android
{ {
@@ -283,7 +284,7 @@ namespace keepass2android
if ((intent.Action == Intents.ShowNotification) || (intent.Action == Intents.UpdateKeyboard)) if ((intent.Action == Intents.ShowNotification) || (intent.Action == Intents.UpdateKeyboard))
{ {
String uuidBytes = intent.GetStringExtra(EntryActivity.KeyEntry); String uuidBytes = intent.GetStringExtra(EntryActivity.KeyEntry);
String searchUrl = intent.GetStringExtra(SearchUrlTask.UrlToSearchKey); String searchUrl = intent.GetStringExtra(SearchUrlTask.UrlToSearchKey);
PwUuid entryId = PwUuid.Zero; PwUuid entryId = PwUuid.Zero;
if (uuidBytes != null) if (uuidBytes != null)
@@ -292,19 +293,21 @@ namespace keepass2android
PwEntryOutput entry; PwEntryOutput entry;
try try
{ {
if ((App.Kp2a.GetDb().LastOpenedEntry != null) if ((App.Kp2a.LastOpenedEntry != null)
&& (entryId.Equals(App.Kp2a.GetDb().LastOpenedEntry.Uuid))) && (entryId.Equals(App.Kp2a.LastOpenedEntry.Uuid)))
{ {
entry = App.Kp2a.GetDb().LastOpenedEntry; entry = App.Kp2a.LastOpenedEntry;
} }
else else
{ {
entry = new PwEntryOutput(App.Kp2a.GetDb().Entries[entryId], App.Kp2a.GetDb().KpDatabase); Database entryDb = App.Kp2a.FindDatabaseForEntryId(entryId);
entry = new PwEntryOutput(entryDb.Entries[entryId], entryDb);
} }
} }
catch (Exception) catch (Exception e)
{ {
Kp2aLog.LogUnexpectedError(e);
//seems like restarting the service happened after closing the DB //seems like restarting the service happened after closing the DB
StopSelf(); StopSelf();
return StartCommandResult.NotSticky; return StartCommandResult.NotSticky;
@@ -400,9 +403,10 @@ namespace keepass2android
var hadKeyboardData = ClearNotifications(); var hadKeyboardData = ClearNotifications();
String entryName = entry.OutputStrings.ReadSafe(PwDefs.TitleField); String entryName = entry.OutputStrings.ReadSafe(PwDefs.TitleField);
Database db = App.Kp2a.FindDatabaseForEntryId(entry.Uuid);
var bmp = Util.DrawableToBitmap(App.Kp2a.GetDb().DrawableFactory.GetIconDrawable(this, var bmp = Util.DrawableToBitmap(db.DrawableFactory.GetIconDrawable(this,
App.Kp2a.GetDb().KpDatabase, entry.Entry.IconId, entry.Entry.CustomIconUuid, false)); db.KpDatabase, entry.Entry.IconId, entry.Entry.CustomIconUuid, false));
if (!(((entry.Entry.CustomIconUuid != null) && (!entry.Entry.CustomIconUuid.Equals(PwUuid.Zero)))) if (!(((entry.Entry.CustomIconUuid != null) && (!entry.Entry.CustomIconUuid.Equals(PwUuid.Zero))))
@@ -807,7 +811,7 @@ namespace keepass2android
//check if we have a last opened entry //check if we have a last opened entry
//this should always be non-null, but if the OS has killed the app, it might occur. //this should always be non-null, but if the OS has killed the app, it might occur.
if (App.Kp2a.GetDb().LastOpenedEntry == null) if (App.Kp2a.LastOpenedEntry == null)
{ {
Intent i = new Intent(context, typeof(AppKilledInfo)); Intent i = new Intent(context, typeof(AppKilledInfo));
i.SetFlags(ActivityFlags.ClearTask | ActivityFlags.NewTask); i.SetFlags(ActivityFlags.ClearTask | ActivityFlags.NewTask);
@@ -817,7 +821,7 @@ namespace keepass2android
if (action.Equals(Intents.CopyUsername)) if (action.Equals(Intents.CopyUsername))
{ {
String username = App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.ReadSafe(PwDefs.UserNameField); String username = App.Kp2a.LastOpenedEntry.OutputStrings.ReadSafe(PwDefs.UserNameField);
if (username.Length > 0) if (username.Length > 0)
{ {
CopyToClipboardService.CopyValueToClipboardWithTimeout(context, username); CopyToClipboardService.CopyValueToClipboardWithTimeout(context, username);
@@ -826,7 +830,7 @@ namespace keepass2android
} }
else if (action.Equals(Intents.CopyPassword)) else if (action.Equals(Intents.CopyPassword))
{ {
String password = App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.ReadSafe(PwDefs.PasswordField); String password = App.Kp2a.LastOpenedEntry.OutputStrings.ReadSafe(PwDefs.PasswordField);
if (password.Length > 0) if (password.Length > 0)
{ {
CopyToClipboardService.CopyValueToClipboardWithTimeout(context, password); CopyToClipboardService.CopyValueToClipboardWithTimeout(context, password);

View File

@@ -28,7 +28,7 @@ namespace keepass2android.services.Kp2aAutofill
{ {
//launch FileSelectActivity (which is root of the stack (exception: we're even below!)) with the appropriate task. //launch FileSelectActivity (which is root of the stack (exception: we're even below!)) with the appropriate task.
//will return the results later //will return the results later
Intent i = new Intent(this, typeof(FileSelectActivity)); Intent i = new Intent(this, typeof(SelectCurrentDbActivity));
//don't show user notifications when an entry is opened. //don't show user notifications when an entry is opened.
var task = new SearchUrlTask() { UrlToSearchFor = requestedUrl, ShowUserNotifications = false, AutoReturnFromQuery = autoReturnFromQuery }; var task = new SearchUrlTask() { UrlToSearchFor = requestedUrl, ShowUserNotifications = false, AutoReturnFromQuery = autoReturnFromQuery };
task.ToIntent(i); task.ToIntent(i);
@@ -39,9 +39,9 @@ namespace keepass2android.services.Kp2aAutofill
protected override FilledAutofillFieldCollection GetDataset(Intent data) protected override FilledAutofillFieldCollection GetDataset(Intent data)
{ {
if (App.Kp2a.GetDb()==null || (App.Kp2a.QuickLocked)) if (App.Kp2a.CurrentDb==null || (App.Kp2a.QuickLocked))
return null; return null;
var entryOutput = App.Kp2a.GetDb().LastOpenedEntry; var entryOutput = App.Kp2a.LastOpenedEntry;
return GetFilledAutofillFieldCollectionFromEntry(entryOutput, this); return GetFilledAutofillFieldCollectionFromEntry(entryOutput, this);
} }

View File

@@ -33,9 +33,9 @@ namespace keepass2android.services
protected override FilledAutofillFieldCollection GetSuggestedEntry(string query) protected override FilledAutofillFieldCollection GetSuggestedEntry(string query)
{ {
if (App.Kp2a.GetDb()?.LastOpenedEntry?.SearchUrl == query) if (App.Kp2a.LastOpenedEntry?.SearchUrl == query)
return ChooseForAutofillActivity.GetFilledAutofillFieldCollectionFromEntry( return ChooseForAutofillActivity.GetFilledAutofillFieldCollectionFromEntry(
App.Kp2a.GetDb()?.LastOpenedEntry, this); App.Kp2a.LastOpenedEntry, this);
return null; return null;
} }
@@ -43,7 +43,7 @@ namespace keepass2android.services
{ {
var intent = new Intent(this, typeof(FileSelectActivity)); var intent = new Intent(this, typeof(SelectCurrentDbActivity));
Dictionary<string, string> outputFields = new Dictionary<string, string>(); Dictionary<string, string> outputFields = new Dictionary<string, string>();
foreach (var p in parser.ClientFormData.HintMap) foreach (var p in parser.ClientFormData.HintMap)

View File

@@ -26,7 +26,7 @@ namespace keepass2android.services
public Intent GetRestartAppIntent(Context context) public Intent GetRestartAppIntent(Context context)
{ {
var intent = new Intent(context, typeof(FileSelectActivity)); var intent = new Intent(context, typeof(SelectCurrentDbActivity));
intent.AddFlags(ActivityFlags.ForwardResult); intent.AddFlags(ActivityFlags.ForwardResult);
return intent; return intent;
} }

View File

@@ -97,7 +97,7 @@ namespace keepass2android
Kp2aLog.Log("OngoingNotificationsService.OnTaskRemoved: " + rootIntent.Action); Kp2aLog.Log("OngoingNotificationsService.OnTaskRemoved: " + rootIntent.Action);
// If the user has closed the task (probably by swiping it out of the recent apps list) then lock the database // If the user has closed the task (probably by swiping it out of the recent apps list) then lock the database
App.Kp2a.LockDatabase(); App.Kp2a.Lock();
} }
public override void OnDestroy() public override void OnDestroy()
@@ -111,7 +111,7 @@ namespace keepass2android
// If the service is killed, then lock the database immediately // If the service is killed, then lock the database immediately
if (App.Kp2a.DatabaseIsUnlocked) if (App.Kp2a.DatabaseIsUnlocked)
{ {
App.Kp2a.LockDatabase(false); App.Kp2a.Lock(false);
} }
UnregisterReceiver(_screenOffReceiver); UnregisterReceiver(_screenOffReceiver);
@@ -228,16 +228,22 @@ namespace keepass2android
private static string GetDatabaseName() private static string GetDatabaseName()
{ {
string displayString = "";
foreach (Database db in App.Kp2a.OpenDatabases)
{
var kpDatabase = db.KpDatabase;
var dbname = kpDatabase.Name;
if (String.IsNullOrEmpty(dbname))
{
//todo: if paranoid ("don't remember recent files") return "***"
dbname = App.Kp2a.GetFileStorage(kpDatabase.IOConnectionInfo).GetFilenameWithoutPathAndExt(kpDatabase.IOConnectionInfo);
}
if (displayString != "")
displayString = displayString + ", ";
displayString += dbname;
}
var db = App.Kp2a.GetDb().KpDatabase; return displayString;
var name = db.Name;
if (String.IsNullOrEmpty(name))
{
//todo: if paranoid ("don't remember recent files") return "***"
name = App.Kp2a.GetFileStorage(db.IOConnectionInfo).GetFilenameWithoutPathAndExt(db.IOConnectionInfo);
}
return name;
} }
#endregion #endregion

View File

@@ -18,8 +18,8 @@ namespace keepass2android.settings
{ {
get get
{ {
var kdfparams = App.Kp2a.GetDb().KpDatabase.KdfParameters; var kdfparams = App.Kp2a.CurrentDb.KpDatabase.KdfParameters;
var kdf = KdfPool.Get(App.Kp2a.GetDb().KpDatabase.KdfParameters.KdfUuid); var kdf = KdfPool.Get(App.Kp2a.CurrentDb.KpDatabase.KdfParameters.KdfUuid);
if (!(kdf is Argon2Kdf)) if (!(kdf is Argon2Kdf))
{ {
new Argon2Kdf().GetDefaultParameters(); new Argon2Kdf().GetDefaultParameters();
@@ -29,7 +29,7 @@ namespace keepass2android.settings
} }
set set
{ {
App.Kp2a.GetDb().KpDatabase.KdfParameters.SetUInt64(Argon2Kdf.ParamIterations, value); App.Kp2a.CurrentDb.KpDatabase.KdfParameters.SetUInt64(Argon2Kdf.ParamIterations, value);
} }
} }
} }
@@ -50,8 +50,8 @@ namespace keepass2android.settings
{ {
get get
{ {
var kdfparams = App.Kp2a.GetDb().KpDatabase.KdfParameters; var kdfparams = App.Kp2a.CurrentDb.KpDatabase.KdfParameters;
var kdf = KdfPool.Get(App.Kp2a.GetDb().KpDatabase.KdfParameters.KdfUuid); var kdf = KdfPool.Get(App.Kp2a.CurrentDb.KpDatabase.KdfParameters.KdfUuid);
if (!(kdf is Argon2Kdf)) if (!(kdf is Argon2Kdf))
{ {
new Argon2Kdf().GetDefaultParameters(); new Argon2Kdf().GetDefaultParameters();
@@ -61,7 +61,7 @@ namespace keepass2android.settings
} }
set set
{ {
App.Kp2a.GetDb().KpDatabase.KdfParameters.SetUInt32(Argon2Kdf.ParamParallelism, (uint) value); App.Kp2a.CurrentDb.KpDatabase.KdfParameters.SetUInt32(Argon2Kdf.ParamParallelism, (uint) value);
} }
} }
} }
@@ -82,8 +82,8 @@ namespace keepass2android.settings
{ {
get get
{ {
var kdfparams = App.Kp2a.GetDb().KpDatabase.KdfParameters; var kdfparams = App.Kp2a.CurrentDb.KpDatabase.KdfParameters;
var kdf = KdfPool.Get(App.Kp2a.GetDb().KpDatabase.KdfParameters.KdfUuid); var kdf = KdfPool.Get(App.Kp2a.CurrentDb.KpDatabase.KdfParameters.KdfUuid);
if (!(kdf is Argon2Kdf)) if (!(kdf is Argon2Kdf))
{ {
new Argon2Kdf().GetDefaultParameters(); new Argon2Kdf().GetDefaultParameters();
@@ -93,7 +93,7 @@ namespace keepass2android.settings
} }
set set
{ {
App.Kp2a.GetDb().KpDatabase.KdfParameters.SetUInt64(Argon2Kdf.ParamMemory, value); App.Kp2a.CurrentDb.KpDatabase.KdfParameters.SetUInt64(Argon2Kdf.ParamMemory, value);
} }
} }
} }

View File

@@ -423,7 +423,7 @@ namespace keepass2android
FindPreference(GetString(Resource.String.design_key)).PreferenceChange += (sender, args) => Activity.Recreate(); FindPreference(GetString(Resource.String.design_key)).PreferenceChange += (sender, args) => Activity.Recreate();
Database db = App.Kp2a.GetDb(); Database db = App.Kp2a.CurrentDb;
if (db != null) if (db != null)
{ {
ListPreference kdfPref = (ListPreference) FindPreference(GetString(Resource.String.kdf_key)); ListPreference kdfPref = (ListPreference) FindPreference(GetString(Resource.String.kdf_key));
@@ -457,7 +457,7 @@ namespace keepass2android
algorithmPref.SetValueIndex(algoValues.Select((v, i) => new { kdf = v, index = i }).First(el => el.kdf == db.KpDatabase.DataCipherUuid.ToHexString()).index); algorithmPref.SetValueIndex(algoValues.Select((v, i) => new { kdf = v, index = i }).First(el => el.kdf == db.KpDatabase.DataCipherUuid.ToHexString()).index);
algorithmPref.PreferenceChange += AlgorithmPrefChange; algorithmPref.PreferenceChange += AlgorithmPrefChange;
algorithmPref.Summary = algorithmPref.Summary =
CipherPool.GlobalPool.GetCipher(App.Kp2a.GetDb().KpDatabase.DataCipherUuid).DisplayName; CipherPool.GlobalPool.GetCipher(App.Kp2a.CurrentDb.KpDatabase.DataCipherUuid).DisplayName;
UpdateImportDbPref(); UpdateImportDbPref();
UpdateImportKeyfilePref(); UpdateImportKeyfilePref();
} }
@@ -504,8 +504,8 @@ namespace keepass2android
FindPreference("IconSetKey").PreferenceChange += (sender, args) => FindPreference("IconSetKey").PreferenceChange += (sender, args) =>
{ {
if (App.Kp2a.GetDb() != null) if (App.Kp2a.CurrentDb!= null)
App.Kp2a.GetDb().DrawableFactory.Clear(); App.Kp2a.CurrentDb.DrawableFactory.Clear();
}; };
@@ -565,11 +565,11 @@ namespace keepass2android
private void AlgorithmPrefChange(object sender, Preference.PreferenceChangeEventArgs preferenceChangeEventArgs) private void AlgorithmPrefChange(object sender, Preference.PreferenceChangeEventArgs preferenceChangeEventArgs)
{ {
var db = App.Kp2a.GetDb(); var db = App.Kp2a.CurrentDb;
var previousCipher = db.KpDatabase.DataCipherUuid; var previousCipher = db.KpDatabase.DataCipherUuid;
db.KpDatabase.DataCipherUuid = new PwUuid(MemUtil.HexStringToByteArray((string)preferenceChangeEventArgs.NewValue)); db.KpDatabase.DataCipherUuid = new PwUuid(MemUtil.HexStringToByteArray((string)preferenceChangeEventArgs.NewValue));
SaveDb save = new SaveDb(Activity, App.Kp2a, new ActionOnFinish(Activity, (success, message, activity) => SaveDb save = new SaveDb(Activity, App.Kp2a, App.Kp2a.CurrentDb, new ActionOnFinish(Activity, (success, message, activity) =>
{ {
if (!success) if (!success)
{ {
@@ -586,7 +586,7 @@ namespace keepass2android
private void UpdateKdfScreen() private void UpdateKdfScreen()
{ {
var db = App.Kp2a.GetDb(); var db = App.Kp2a.CurrentDb;
var kdf = KdfPool.Get(db.KpDatabase.KdfParameters.KdfUuid); var kdf = KdfPool.Get(db.KpDatabase.KdfParameters.KdfUuid);
var kdfpref = FindPreference(GetString(Resource.String.kdf_key)); var kdfpref = FindPreference(GetString(Resource.String.kdf_key));
@@ -624,7 +624,7 @@ namespace keepass2android
private void OnKdfChange(object sender, Preference.PreferenceChangeEventArgs preferenceChangeEventArgs) private void OnKdfChange(object sender, Preference.PreferenceChangeEventArgs preferenceChangeEventArgs)
{ {
var db = App.Kp2a.GetDb(); var db = App.Kp2a.CurrentDb;
var previousKdfParams = db.KpDatabase.KdfParameters; var previousKdfParams = db.KpDatabase.KdfParameters;
Kp2aLog.Log("previous kdf: " + KdfPool.Get(db.KpDatabase.KdfParameters.KdfUuid) + " " + db.KpDatabase.KdfParameters.KdfUuid.ToHexString() ); Kp2aLog.Log("previous kdf: " + KdfPool.Get(db.KpDatabase.KdfParameters.KdfUuid) + " " + db.KpDatabase.KdfParameters.KdfUuid.ToHexString() );
db.KpDatabase.KdfParameters = db.KpDatabase.KdfParameters =
@@ -634,7 +634,7 @@ namespace keepass2android
Kp2aLog.Log("--new kdf: " + KdfPool.Get(db.KpDatabase.KdfParameters.KdfUuid) + " " + db.KpDatabase.KdfParameters.KdfUuid.ToHexString()); Kp2aLog.Log("--new kdf: " + KdfPool.Get(db.KpDatabase.KdfParameters.KdfUuid) + " " + db.KpDatabase.KdfParameters.KdfUuid.ToHexString());
SaveDb save = new SaveDb(Activity, App.Kp2a, new ActionOnFinish(Activity, (success, message, activity) => SaveDb save = new SaveDb(Activity, App.Kp2a, App.Kp2a.CurrentDb, new ActionOnFinish(Activity, (success, message, activity) =>
{ {
if (!success) if (!success)
{ {
@@ -669,7 +669,7 @@ namespace keepass2android
private void PrepareTemplates(Database db) private void PrepareTemplates(Database db)
{ {
Preference pref = FindPreference("AddTemplates_pref_key"); Preference pref = FindPreference("AddTemplates_pref_key");
if ((!db.DatabaseFormat.SupportsTemplates) || (AddTemplateEntries.ContainsAllTemplates(App.Kp2a))) if ((!db.DatabaseFormat.SupportsTemplates) || (AddTemplateEntries.ContainsAllTemplates(App.Kp2a.CurrentDb)))
{ {
pref.Enabled = false; pref.Enabled = false;
} }
@@ -692,7 +692,7 @@ namespace keepass2android
private void PrepareMasterPassword() private void PrepareMasterPassword()
{ {
Preference changeMaster = FindPreference(GetString(Resource.String.master_pwd_key)); Preference changeMaster = FindPreference(GetString(Resource.String.master_pwd_key));
if (App.Kp2a.GetDb().CanWrite) if (App.Kp2a.CurrentDb.CanWrite)
{ {
changeMaster.Enabled = true; changeMaster.Enabled = true;
changeMaster.PreferenceClick += delegate { new SetPasswordDialog(Activity).Show(); }; changeMaster.PreferenceClick += delegate { new SetPasswordDialog(Activity).Show(); };
@@ -717,7 +717,7 @@ namespace keepass2android
String previousName = db.KpDatabase.Name; String previousName = db.KpDatabase.Name;
db.KpDatabase.Name = e.NewValue.ToString(); db.KpDatabase.Name = e.NewValue.ToString();
SaveDb save = new SaveDb(Activity, App.Kp2a, new ActionOnFinish(Activity, (success, message, activity) => SaveDb save = new SaveDb(Activity, App.Kp2a, App.Kp2a.CurrentDb, new ActionOnFinish(Activity, (success, message, activity) =>
{ {
if (!success) if (!success)
{ {
@@ -755,7 +755,7 @@ namespace keepass2android
String previousUsername = db.KpDatabase.DefaultUserName; String previousUsername = db.KpDatabase.DefaultUserName;
db.KpDatabase.DefaultUserName = e.NewValue.ToString(); db.KpDatabase.DefaultUserName = e.NewValue.ToString();
SaveDb save = new SaveDb(Activity, App.Kp2a, new ActionOnFinish(Activity, (success, message, activity) => SaveDb save = new SaveDb(Activity, App.Kp2a, App.Kp2a.CurrentDb, new ActionOnFinish(Activity, (success, message, activity) =>
{ {
if (!success) if (!success)
{ {
@@ -791,8 +791,8 @@ namespace keepass2android
private void OnUseOfflineCacheChanged(object sender, Preference.PreferenceChangeEventArgs e) private void OnUseOfflineCacheChanged(object sender, Preference.PreferenceChangeEventArgs e)
{ {
//ensure the user gets a matching database //ensure the user gets a matching database
if (App.Kp2a.GetDb() != null && !App.Kp2a.GetDb().Ioc.IsLocalFile()) if (App.Kp2a.CurrentDb!= null && !App.Kp2a.CurrentDb.Ioc.IsLocalFile())
App.Kp2a.LockDatabase(false); App.Kp2a.LockSingleDatabase(App.Kp2a.CurrentDb, false);
if (!(bool)e.NewValue) if (!(bool)e.NewValue)
{ {
@@ -842,7 +842,7 @@ namespace keepass2android
importDb.Enabled = false; importDb.Enabled = false;
return; return;
} }
CompositeKey masterKey = App.Kp2a.GetDb().KpDatabase.MasterKey; CompositeKey masterKey = App.Kp2a.CurrentDb.KpDatabase.MasterKey;
if (masterKey.ContainsType(typeof(KcpKeyFile))) if (masterKey.ContainsType(typeof(KcpKeyFile)))
{ {
IOConnectionInfo iocKeyfile = ((KcpKeyFile)masterKey.GetUserKey(typeof(KcpKeyFile))).Ioc; IOConnectionInfo iocKeyfile = ((KcpKeyFile)masterKey.GetUserKey(typeof(KcpKeyFile))).Ioc;
@@ -871,12 +871,12 @@ namespace keepass2android
{ {
try try
{ {
CompositeKey masterKey = App.Kp2a.GetDb().KpDatabase.MasterKey; CompositeKey masterKey = App.Kp2a.CurrentDb.KpDatabase.MasterKey;
var sourceIoc = ((KcpKeyFile)masterKey.GetUserKey(typeof(KcpKeyFile))).Ioc; var sourceIoc = ((KcpKeyFile)masterKey.GetUserKey(typeof(KcpKeyFile))).Ioc;
var newIoc = IoUtil.ImportFileToInternalDirectory(sourceIoc, Activity, App.Kp2a); var newIoc = IoUtil.ImportFileToInternalDirectory(sourceIoc, Activity, App.Kp2a);
((KcpKeyFile)masterKey.GetUserKey(typeof(KcpKeyFile))).ResetIoc(newIoc); ((KcpKeyFile)masterKey.GetUserKey(typeof(KcpKeyFile))).ResetIoc(newIoc);
var keyfileString = IOConnectionInfo.SerializeToString(newIoc); var keyfileString = IOConnectionInfo.SerializeToString(newIoc);
App.Kp2a.StoreOpenedFileAsRecent(App.Kp2a.GetDb().Ioc, keyfileString); App.Kp2a.StoreOpenedFileAsRecent(App.Kp2a.CurrentDb.Ioc, keyfileString);
return () => return () =>
{ {
UpdateImportKeyfilePref(); UpdateImportKeyfilePref();
@@ -914,7 +914,7 @@ namespace keepass2android
//Import db/key file preferences: //Import db/key file preferences:
Preference importDb = FindPreference("import_db_prefs"); Preference importDb = FindPreference("import_db_prefs");
bool isLocalOrContent = bool isLocalOrContent =
App.Kp2a.GetDb().Ioc.IsLocalFile() || App.Kp2a.GetDb().Ioc.Path.StartsWith("content://"); App.Kp2a.CurrentDb.Ioc.IsLocalFile() || App.Kp2a.CurrentDb.Ioc.Path.StartsWith("content://");
if (!isLocalOrContent) if (!isLocalOrContent)
{ {
importDb.Summary = GetString(Resource.String.OnlyAvailableForLocalFiles); importDb.Summary = GetString(Resource.String.OnlyAvailableForLocalFiles);
@@ -922,7 +922,7 @@ namespace keepass2android
} }
else else
{ {
if (IoUtil.IsInInternalDirectory(App.Kp2a.GetDb().Ioc.Path, Activity)) if (IoUtil.IsInInternalDirectory(App.Kp2a.CurrentDb.Ioc.Path, Activity))
{ {
importDb.Summary = GetString(Resource.String.FileIsInInternalDirectory); importDb.Summary = GetString(Resource.String.FileIsInInternalDirectory);
importDb.Enabled = false; importDb.Enabled = false;
@@ -941,7 +941,7 @@ namespace keepass2android
{ {
try try
{ {
var sourceIoc = App.Kp2a.GetDb().Ioc; var sourceIoc = App.Kp2a.CurrentDb.Ioc;
var newIoc = IoUtil.ImportFileToInternalDirectory(sourceIoc, Activity, App.Kp2a); var newIoc = IoUtil.ImportFileToInternalDirectory(sourceIoc, Activity, App.Kp2a);
return () => return () =>
{ {
@@ -949,7 +949,12 @@ namespace keepass2android
builder builder
.SetMessage(Resource.String.DatabaseFileMoved); .SetMessage(Resource.String.DatabaseFileMoved);
builder.SetPositiveButton(Android.Resource.String.Ok, (sender, args) => builder.SetPositiveButton(Android.Resource.String.Ok, (sender, args) =>
PasswordActivity.Launch(Activity, newIoc, new NullTask(), App.Kp2a.GetDb().KpDatabase.MasterKey)); {
var key = App.Kp2a.CurrentDb.KpDatabase.MasterKey;
App.Kp2a.CloseDatabase(App.Kp2a.CurrentDb);
PasswordActivity.Launch(Activity, newIoc, new NullTask(), key);
});
builder.Show(); builder.Show();
}; };

View File

@@ -77,7 +77,7 @@ namespace keepass2android.settings
paramValue = 1; paramValue = 1;
} }
Database db = App.Kp2a.GetDb(); Database db = App.Kp2a.CurrentDb;
ulong oldValue = ParamValue; ulong oldValue = ParamValue;
@@ -89,7 +89,7 @@ namespace keepass2android.settings
ParamValue = paramValue; ParamValue = paramValue;
Handler handler = new Handler(); Handler handler = new Handler();
SaveDb save = new SaveDb((Activity)Context, App.Kp2a, new KdfNumberParamPreference.AfterSave((Activity)Context, handler, oldValue, this)); SaveDb save = new SaveDb((Activity)Context, App.Kp2a, App.Kp2a.CurrentDb, new KdfNumberParamPreference.AfterSave((Activity)Context, handler, oldValue, this));
ProgressTask pt = new ProgressTask(App.Kp2a, (Activity)Context, save); ProgressTask pt = new ProgressTask(App.Kp2a, (Activity)Context, save);
pt.Run(); pt.Run();
@@ -118,7 +118,7 @@ namespace keepass2android.settings
} else { } else {
DisplayMessage(_ctx); DisplayMessage(_ctx);
App.Kp2a.GetDb().KpDatabase.KdfParameters.SetUInt64(AesKdf.ParamRounds, _oldRounds); App.Kp2a.CurrentDb.KpDatabase.KdfParameters.SetUInt64(AesKdf.ParamRounds, _oldRounds);
} }
base.Run(); base.Run();
@@ -140,18 +140,18 @@ namespace keepass2android.settings
get get
{ {
AesKdf kdf = new AesKdf(); AesKdf kdf = new AesKdf();
if (!kdf.Uuid.Equals(App.Kp2a.GetDb().KpDatabase.KdfParameters.KdfUuid)) if (!kdf.Uuid.Equals(App.Kp2a.CurrentDb.KpDatabase.KdfParameters.KdfUuid))
return (uint) PwDefs.DefaultKeyEncryptionRounds; return (uint) PwDefs.DefaultKeyEncryptionRounds;
else else
{ {
ulong uRounds = App.Kp2a.GetDb().KpDatabase.KdfParameters.GetUInt64( ulong uRounds = App.Kp2a.CurrentDb.KpDatabase.KdfParameters.GetUInt64(
AesKdf.ParamRounds, PwDefs.DefaultKeyEncryptionRounds); AesKdf.ParamRounds, PwDefs.DefaultKeyEncryptionRounds);
uRounds = Math.Min(uRounds, 0xFFFFFFFEUL); uRounds = Math.Min(uRounds, 0xFFFFFFFEUL);
return (uint) uRounds; return (uint) uRounds;
} }
} }
set { App.Kp2a.GetDb().KpDatabase.KdfParameters.SetUInt64(AesKdf.ParamRounds, value); } set { App.Kp2a.CurrentDb.KpDatabase.KdfParameters.SetUInt64(AesKdf.ParamRounds, value); }
} }
public RoundsPreference(Context context, IAttributeSet attrs):base(context, attrs) public RoundsPreference(Context context, IAttributeSet attrs):base(context, attrs)

View File

@@ -83,7 +83,7 @@ namespace keepass2android
public static void Resume(Activity act) public static void Resume(Activity act)
{ {
if ( App.Kp2a.GetDb() != null) if ( App.Kp2a.CurrentDb!= null)
{ {
Timeout.Cancel(act); Timeout.Cancel(act);
} }
@@ -92,14 +92,13 @@ namespace keepass2android
static bool IocChanged(IOConnectionInfo ioc, IOConnectionInfo other) static bool IocChanged(IOConnectionInfo ioc, IOConnectionInfo other)
{ {
if ((ioc == null) || (other == null)) return false; if ((ioc == null) || (other == null)) return false;
return ioc.GetDisplayName() != other.GetDisplayName(); return !ioc.IsSameFileAs(other);
} }
public static bool CheckShutdown(Activity act, IOConnectionInfo ioc) { public static bool CheckDbChanged(Activity act, IOConnectionInfo ioc) {
if (( !App.Kp2a.DatabaseIsUnlocked ) if (( !App.Kp2a.DatabaseIsUnlocked )
|| (IocChanged(ioc, App.Kp2a.GetDb().Ioc))) //file was changed from ActionSend-Intent || (IocChanged(ioc, App.Kp2a.CurrentDb.Ioc))) //file was changed from ActionSend-Intent
{ {
App.Kp2a.LockDatabase();
return true; return true;
} }
return false; return false;

View File

@@ -71,8 +71,9 @@ namespace keepass2android.view
_textView = (TextView)ev.FindViewById(Resource.Id.entry_text); _textView = (TextView)ev.FindViewById(Resource.Id.entry_text);
_textView.TextSize = PrefsUtil.GetListTextSize(groupActivity); _textView.TextSize = PrefsUtil.GetListTextSize(groupActivity);
Database db = App.Kp2a.FindDatabaseForEntryId(pw.Uuid);
ev.FindViewById(Resource.Id.entry_icon_bkg).Visibility = App.Kp2a.GetDb().DrawableFactory.IsWhiteIconSet ? ViewStates.Visible : ViewStates.Gone; ev.FindViewById(Resource.Id.entry_icon_bkg).Visibility = db.DrawableFactory.IsWhiteIconSet ? ViewStates.Visible : ViewStates.Gone;
_textviewDetails = (TextView)ev.FindViewById(Resource.Id.entry_text_detail); _textviewDetails = (TextView)ev.FindViewById(Resource.Id.entry_text_detail);
_textviewDetails.TextSize = PrefsUtil.GetListDetailTextSize(groupActivity); _textviewDetails.TextSize = PrefsUtil.GetListDetailTextSize(groupActivity);
@@ -106,15 +107,16 @@ namespace keepass2android.view
ev.FindViewById(Resource.Id.icon).Visibility = ViewStates.Visible; ev.FindViewById(Resource.Id.icon).Visibility = ViewStates.Visible;
ev.FindViewById(Resource.Id.check_mark).Visibility = ViewStates.Invisible; ev.FindViewById(Resource.Id.check_mark).Visibility = ViewStates.Invisible;
Database db = App.Kp2a.FindDatabaseForEntryId(_entry.Uuid);
ImageView iv = (ImageView)ev.FindViewById(Resource.Id.icon); ImageView iv = (ImageView)ev.FindViewById(Resource.Id.icon);
bool isExpired = pw.Expires && pw.ExpiryTime < DateTime.Now; bool isExpired = pw.Expires && pw.ExpiryTime < DateTime.Now;
if (isExpired) if (isExpired)
{ {
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iv, Context, App.Kp2a.GetDb().KpDatabase, PwIcon.Expired, PwUuid.Zero, false); db.DrawableFactory.AssignDrawableTo(iv, Context, db.KpDatabase, PwIcon.Expired, PwUuid.Zero, false);
} else } else
{ {
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iv, Context, App.Kp2a.GetDb().KpDatabase, pw.IconId, pw.CustomIconUuid, false); db.DrawableFactory.AssignDrawableTo(iv, Context, db.KpDatabase, pw.IconId, pw.CustomIconUuid, false);
} }
String title = pw.Strings.ReadSafe(PwDefs.TitleField); String title = pw.Strings.ReadSafe(PwDefs.TitleField);
@@ -138,7 +140,7 @@ namespace keepass2android.view
_textView.SetTextColor(new Color((int)_defaultTextColor)); _textView.SetTextColor(new Color((int)_defaultTextColor));
String detail = pw.Strings.ReadSafe(PwDefs.UserNameField); String detail = pw.Strings.ReadSafe(PwDefs.UserNameField);
detail = SprEngine.Compile(detail, new SprContext(_entry, App.Kp2a.GetDb().KpDatabase, SprCompileFlags.All)); detail = SprEngine.Compile(detail, new SprContext(_entry, db.KpDatabase, SprCompileFlags.All));
if ((_showDetail == false) || (String.IsNullOrEmpty(detail))) if ((_showDetail == false) || (String.IsNullOrEmpty(detail)))
{ {

View File

@@ -63,7 +63,9 @@ namespace keepass2android.view
_label = (TextView) gv.FindViewById(Resource.Id.group_label); _label = (TextView) gv.FindViewById(Resource.Id.group_label);
_label.TextSize = size-8; _label.TextSize = size-8;
gv.FindViewById(Resource.Id.group_icon_bkg).Visibility = App.Kp2a.GetDb().DrawableFactory.IsWhiteIconSet ? ViewStates.Visible : ViewStates.Gone; Database db = App.Kp2a.FindDatabaseForGroupId(pw.Uuid);
gv.FindViewById(Resource.Id.group_icon_bkg).Visibility = db.DrawableFactory.IsWhiteIconSet ? ViewStates.Visible : ViewStates.Gone;
gv.FindViewById(Resource.Id.icon).Visibility = ViewStates.Visible; gv.FindViewById(Resource.Id.icon).Visibility = ViewStates.Visible;
gv.FindViewById(Resource.Id.check_mark).Visibility = ViewStates.Invisible; gv.FindViewById(Resource.Id.check_mark).Visibility = ViewStates.Invisible;
@@ -79,7 +81,8 @@ namespace keepass2android.view
_pwGroup = pw; _pwGroup = pw;
ImageView iv = (ImageView) gv.FindViewById(Resource.Id.icon); ImageView iv = (ImageView) gv.FindViewById(Resource.Id.icon);
App.Kp2a.GetDb().DrawableFactory.AssignDrawableTo(iv, _groupBaseActivity, App.Kp2a.GetDb().KpDatabase, pw.IconId, pw.CustomIconUuid, true); Database db = App.Kp2a.FindDatabaseForGroupId(pw.Uuid);
db.DrawableFactory.AssignDrawableTo(iv, _groupBaseActivity, db.KpDatabase, pw.IconId, pw.CustomIconUuid, true);
gv.FindViewById(Resource.Id.icon).Visibility = ViewStates.Visible; gv.FindViewById(Resource.Id.icon).Visibility = ViewStates.Visible;
gv.FindViewById(Resource.Id.check_mark).Visibility = ViewStates.Invisible; gv.FindViewById(Resource.Id.check_mark).Visibility = ViewStates.Invisible;