diff --git a/src/KeePassLib2Android/Native/NativeLib.cs b/src/KeePassLib2Android/Native/NativeLib.cs
index 8cda400c..05a812ff 100644
--- a/src/KeePassLib2Android/Native/NativeLib.cs
+++ b/src/KeePassLib2Android/Native/NativeLib.cs
@@ -164,7 +164,6 @@ namespace KeePassLib.Native
try
{
- //Kp2aLog.Log("4+1"+new Kp2atest.TestClass().Add1(4));
Com.Keepassdroid.Crypto.Finalkey.NativeFinalKey key = new Com.Keepassdroid.Crypto.Finalkey.NativeFinalKey();
byte[] newKey = key.TransformMasterKey(pKey256, pBuf256, (int)uRounds);
diff --git a/src/KeePassLib2Android/PwDatabase.cs b/src/KeePassLib2Android/PwDatabase.cs
index 925ab468..1172027c 100644
--- a/src/KeePassLib2Android/PwDatabase.cs
+++ b/src/KeePassLib2Android/PwDatabase.cs
@@ -562,22 +562,40 @@ namespace KeePassLib
/// Open a database. The URL may point to any supported data source.
///
/// IO connection to load the database from.
- /// Key used to open the specified database.
+ /// sKey used to open the specified database.
/// Logger, which gets all status messages.
public void Open(IOConnectionInfo ioSource, CompositeKey pwKey,
IStatusLogger slLogger)
{
- Debug.Assert(ioSource != null);
- if(ioSource == null) throw new ArgumentNullException("ioSource");
+ Open(IOConnection.OpenRead(ioSource), UrlUtil.StripExtension(
+ UrlUtil.GetFileName(ioSource.Path)), ioSource, pwKey, slLogger );
+
+ }
+
+ ///
+ /// Open a database. The URL may point to any supported data source.
+ ///
+ /// IO connection to load the database from.
+ /// Key used to open the specified database.
+ /// Logger, which gets all status messages.
+ public void Open(Stream s, string fileNameWithoutPathAndExt, IOConnectionInfo ioSource, CompositeKey pwKey,
+ IStatusLogger slLogger)
+ {
+ Debug.Assert(s != null);
+ if (s == null) throw new ArgumentNullException("s");
+ Debug.Assert(fileNameWithoutPathAndExt != null);
+ if (fileNameWithoutPathAndExt == null) throw new ArgumentException("fileNameWithoutPathAndExt");
Debug.Assert(pwKey != null);
- if(pwKey == null) throw new ArgumentNullException("pwKey");
+ Debug.Assert(ioSource != null);
+ if (ioSource == null) throw new ArgumentNullException("ioSource");
+
+ if (pwKey == null) throw new ArgumentNullException("pwKey");
Close();
try
{
- m_pgRootGroup = new PwGroup(true, true, UrlUtil.StripExtension(
- UrlUtil.GetFileName(ioSource.Path)), PwIcon.FolderOpen);
+ m_pgRootGroup = new PwGroup(true, true, fileNameWithoutPathAndExt, PwIcon.FolderOpen);
m_pgRootGroup.IsExpanded = true;
m_pwUserKey = pwKey;
@@ -587,8 +605,8 @@ namespace KeePassLib
KdbxFile kdbx = new KdbxFile(this);
kdbx.DetachBinaries = m_strDetachBins;
- Stream s = IOConnection.OpenRead(ioSource);
kdbx.Load(s, KdbxFormat.Default, slLogger);
+
s.Close();
m_pbHashOfLastIO = kdbx.HashOfFileOnDisk;
@@ -598,13 +616,14 @@ namespace KeePassLib
m_bDatabaseOpened = true;
m_ioSource = ioSource;
}
- catch(Exception)
+ catch (Exception)
{
Clear();
throw;
}
}
+
///
/// Save the currently opened database. The file is written to the location
/// it has been opened from.
@@ -626,7 +645,7 @@ namespace KeePassLib
kdb.Save(s, null, KdbxFormat.Default, slLogger);
ft.CommitWrite();
-
+
m_pbHashOfLastIO = kdb.HashOfFileOnDisk;
m_pbHashOfFileOnDisk = kdb.HashOfFileOnDisk;
Debug.Assert(m_pbHashOfFileOnDisk != null);
@@ -636,6 +655,23 @@ namespace KeePassLib
m_bModified = false;
}
+ ///
+ /// Save the currently opened database. The file is written to the given stream which is expected to be the original location.
+ ///
+ /// This allows to save to cloud locations etc.
+ public void Save(Stream streamOfOriginalLocation, IStatusLogger slLogger)
+ {
+ Debug.Assert(ValidateUuidUniqueness());
+ Stream s = streamOfOriginalLocation;
+ KdbxFile kdb = new KdbxFile(this);
+ kdb.Save(s, null, KdbxFormat.Default, slLogger);
+
+ m_pbHashOfLastIO = kdb.HashOfFileOnDisk;
+ m_pbHashOfFileOnDisk = kdb.HashOfFileOnDisk;
+ Debug.Assert(m_pbHashOfFileOnDisk != null);
+ m_bModified = false;
+ }
+
///
/// Save the currently opened database to a different location. If
/// is true, the specified
diff --git a/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs b/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs
index 03456962..37a2873f 100644
--- a/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs
+++ b/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs
@@ -91,12 +91,18 @@ namespace KeePassLib.Serialization
if((sDecrypted == null) || (sDecrypted == hashedStream))
throw new SecurityException(KLRes.CryptoStreamFailed);
+ if (m_slLogger != null)
+ m_slLogger.SetText("KP2AKEY_TransformingKey", LogStatusType.AdditionalInfo);
+
brDecrypted = new BinaryReaderEx(sDecrypted, encNoBom, KLRes.FileCorrupted);
byte[] pbStoredStartBytes = brDecrypted.ReadBytes(32);
if((m_pbStreamStartBytes == null) || (m_pbStreamStartBytes.Length != 32))
throw new InvalidDataException();
+ if (m_slLogger != null)
+ m_slLogger.SetText("KP2AKEY_DecodingDatabase", LogStatusType.AdditionalInfo);
+
for(int iStart = 0; iStart < 32; ++iStart)
{
if(pbStoredStartBytes[iStart] != m_pbStreamStartBytes[iStart])
@@ -126,7 +132,8 @@ namespace KeePassLib.Serialization
m_pbProtectedStreamKey);
}
else m_randomStream = null; // No random stream for plain-text files
-
+ if (m_slLogger != null)
+ m_slLogger.SetText("KP2AKEY_ParsingDatabase", LogStatusType.AdditionalInfo);
ReadXmlStreamed(readerStream, hashedStream);
// ReadXmlDom(readerStream);
@@ -312,7 +319,8 @@ namespace KeePassLib.Serialization
if(m_pbMasterSeed.Length != 32)
throw new FormatException(KLRes.MasterSeedLengthInvalid);
ms.Write(m_pbMasterSeed, 0, 32);
-
+ if (m_slLogger != null)
+ m_slLogger.SetText("KP2AKEY_TransformingKey", LogStatusType.AdditionalInfo);
byte[] pKey32 = m_pwDatabase.MasterKey.GenerateKey32(m_pbTransformSeed,
m_pwDatabase.KeyEncryptionRounds).ReadData();
if((pKey32 == null) || (pKey32.Length != 32))
diff --git a/src/Kp2aBusinessLogic/IKp2aApp.cs b/src/Kp2aBusinessLogic/IKp2aApp.cs
index b766b110..1951a686 100644
--- a/src/Kp2aBusinessLogic/IKp2aApp.cs
+++ b/src/Kp2aBusinessLogic/IKp2aApp.cs
@@ -2,6 +2,7 @@ using System;
using Android.Content;
using Android.OS;
using KeePassLib.Serialization;
+using keepass2android.Io;
namespace keepass2android
{
@@ -57,5 +58,7 @@ namespace keepass2android
Handler UiThreadHandler { get; }
IProgressDialog CreateProgressDialog(Context ctx);
+ IFileStorage GetFileStorage(IOConnectionInfo iocInfo);
+
}
}
\ No newline at end of file
diff --git a/src/Kp2aBusinessLogic/IProgressDialog.cs b/src/Kp2aBusinessLogic/IProgressDialog.cs
index ac74dad0..1035b195 100644
--- a/src/Kp2aBusinessLogic/IProgressDialog.cs
+++ b/src/Kp2aBusinessLogic/IProgressDialog.cs
@@ -3,7 +3,7 @@ namespace keepass2android
public interface IProgressDialog
{
void SetTitle(string title);
- void SetMessage(string getResourceString);
+ void SetMessage(string resourceString);
void Dismiss();
void Show();
}
diff --git a/src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs b/src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs
new file mode 100644
index 00000000..54ebc266
--- /dev/null
+++ b/src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+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.Serialization;
+using KeePassLib.Utility;
+
+namespace keepass2android.Io
+{
+ public class BuiltInFileStorage: IFileStorage
+ {
+ public void DeleteFile(IOConnectionInfo ioc)
+ {
+ IOConnection.DeleteFile(ioc);
+ }
+
+ public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion)
+ {
+ if (!ioc.IsLocalFile())
+ return false;
+ DateTime previousDate;
+ if (!DateTime.TryParse(previousFileVersion, out previousDate))
+ return false;
+ return File.GetLastWriteTimeUtc(ioc.Path) > previousDate;
+ }
+
+
+ public string GetCurrentFileVersionFast(IOConnectionInfo ioc)
+ {
+
+ if (ioc.IsLocalFile())
+ {
+ return File.GetLastWriteTimeUtc(ioc.Path).ToString(CultureInfo.InvariantCulture);
+ }
+ else
+ {
+ return DateTime.MinValue.ToString(CultureInfo.InvariantCulture);
+ }
+
+
+ }
+
+ public Stream OpenFileForRead(IOConnectionInfo ioc)
+ {
+ return IOConnection.OpenRead(ioc);
+ }
+
+ public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction)
+ {
+ return new BuiltInFileTransaction(ioc, useFileTransaction);
+ }
+
+ public class BuiltInFileTransaction : IWriteTransaction
+ {
+ private readonly FileTransactionEx _transaction;
+
+ public BuiltInFileTransaction(IOConnectionInfo ioc, bool useFileTransaction)
+ {
+ _transaction = new FileTransactionEx(ioc, useFileTransaction);
+ }
+
+ public void Dispose()
+ {
+
+ }
+
+ public Stream OpenFile()
+ {
+ return _transaction.OpenWrite();
+ }
+
+ public void CommitWrite()
+ {
+ _transaction.CommitWrite();
+ }
+ }
+
+ public bool CompleteIoId()
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool? FileExists()
+ {
+ throw new NotImplementedException();
+ }
+
+ public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc)
+ {
+ return UrlUtil.StripExtension(
+ UrlUtil.GetFileName(ioc.Path));
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Kp2aBusinessLogic/Io/IFileStorage.cs b/src/Kp2aBusinessLogic/Io/IFileStorage.cs
new file mode 100644
index 00000000..3a203189
--- /dev/null
+++ b/src/Kp2aBusinessLogic/Io/IFileStorage.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+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.Keys;
+using KeePassLib.Serialization;
+
+namespace keepass2android.Io
+{
+ ///
+ /// Called as a callback from CheckForFileChangeAsync.
+ ///
+ ///
+ ///
+ public delegate void OnCheckForFileChangeCompleted(IOConnectionInfo ioc, bool fileChanged);
+
+ ///
+ /// Interface to encapsulate all access to disk or cloud.
+ ///
+ /// This interface might be implemented for different cloud storage providers in the future to extend the possibilities of the
+ /// "built-in" IOConnection class in the Keepass-Lib.
+ /// Note that it was decided to use the IOConnectionInfo also for cloud storage (unless it turns out that this isn't possible, but
+ /// with prefixes like dropbox:// it should be). The advantage is that the database for saving recent files etc. will then work without
+ /// much work to do. Furthermore, the IOConnectionInfo seems generic info to capture all required data, even though it might be nicer to
+ /// have an IIoStorageId interface in few cases.*/
+ public interface IFileStorage
+ {
+ ///
+ /// Deletes the given file.
+ ///
+ void DeleteFile(IOConnectionInfo ioc);
+
+ ///
+ /// Tests whether the file was changed.
+ ///
+ /// Note: This function may return false even if the file might have changed. The function
+ /// should focus on being fast and cheap instead of doing things like hashing or downloading a full file.
+ /// Returns true if a change was detected, false otherwise.
+ bool CheckForFileChangeFast(IOConnectionInfo ioc , string previousFileVersion);
+
+ ///
+ /// Returns a string describing the "version" of the file specified by ioc.
+ ///
+ /// This string may have a deliberate value (except null) and should not be used by callers except for passing it to
+ /// CheckForFileChangeFast().
+ /// A string which should not be null.
+ string GetCurrentFileVersionFast(IOConnectionInfo ioc);
+
+ Stream OpenFileForRead(IOConnectionInfo ioc);
+ //Stream OpenFileForWrite( IOConnectionInfo ioc, bool useTransaction);
+ IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction);
+
+ ///
+ /// brings up a dialog to query credentials or something like this.
+ ///
+ /// true if success, false if error or cancelled by user
+ bool CompleteIoId( /*in/out ioId*/);
+
+
+ ///
+ /// Checks whether the given file exists.
+ ///
+ /// true if it exists, false if not. Null if the check couldn't be performed (e.g. because no credentials available or no connection established.)
+ bool? FileExists( /*ioId*/);
+
+ string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc);
+ }
+
+ public interface IWriteTransaction: IDisposable
+ {
+ Stream OpenFile();
+ void CommitWrite();
+ }
+}
\ No newline at end of file
diff --git a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj
index 1b8192b6..75a2642a 100644
--- a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj
+++ b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj
@@ -41,6 +41,8 @@
+
+
@@ -68,7 +70,7 @@
-
+
diff --git a/src/Kp2aBusinessLogic/PreferenceKey.cs b/src/Kp2aBusinessLogic/PreferenceKey.cs
index 6e62362a..83a99b4e 100644
--- a/src/Kp2aBusinessLogic/PreferenceKey.cs
+++ b/src/Kp2aBusinessLogic/PreferenceKey.cs
@@ -6,6 +6,7 @@ namespace keepass2android
public enum PreferenceKey
{
remember_keyfile,
- UseFileTransactions
+ UseFileTransactions,
+ CheckForFileChangesOnSave
}
}
\ No newline at end of file
diff --git a/src/Kp2aBusinessLogic/UpdateStatus.cs b/src/Kp2aBusinessLogic/ProgressDialogStatusLogger.cs
similarity index 61%
rename from src/Kp2aBusinessLogic/UpdateStatus.cs
rename to src/Kp2aBusinessLogic/ProgressDialogStatusLogger.cs
index ab711f93..9a650e05 100644
--- a/src/Kp2aBusinessLogic/UpdateStatus.cs
+++ b/src/Kp2aBusinessLogic/ProgressDialogStatusLogger.cs
@@ -25,34 +25,54 @@ namespace keepass2android
///
/// StatusLogger implementation which shows the progress in a progress dialog
///
- public class UpdateStatus: IStatusLogger {
+ public class ProgressDialogStatusLogger: IStatusLogger {
private readonly IProgressDialog _progressDialog;
readonly IKp2aApp _app;
private readonly Handler _handler;
-
- public UpdateStatus() {
+ private string _message = "";
+
+ public ProgressDialogStatusLogger() {
}
- public UpdateStatus(IKp2aApp app, Handler handler, IProgressDialog pd) {
+ public ProgressDialogStatusLogger(IKp2aApp app, Handler handler, IProgressDialog pd) {
_app = app;
_progressDialog = pd;
_handler = handler;
}
public void UpdateMessage(UiStringKey stringKey) {
- if ( _app != null && _progressDialog != null && _handler != null ) {
- _handler.Post( () => {_progressDialog.SetMessage(_app.GetResourceString(stringKey));});
- }
+ if (_app != null)
+ UpdateMessage(_app.GetResourceString(stringKey));
}
public void UpdateMessage (String message)
{
+ _message = message;
if ( _app!= null && _progressDialog != null && _handler != null ) {
_handler.Post(() => {_progressDialog.SetMessage(message); } );
}
}
+ public void UpdateSubMessage(String submessage)
+ {
+ if (_app != null && _progressDialog != null && _handler != null)
+ {
+ _handler.Post(() =>
+ {
+ if (String.IsNullOrEmpty(submessage))
+ {
+ _progressDialog.SetMessage(_message + " (" + submessage + ")");
+ }
+ else
+ {
+ _progressDialog.SetMessage(_message);
+ }
+ }
+ );
+ }
+ }
+
#region IStatusLogger implementation
public void StartLogging (string strOperation, bool bWriteOperationToLog)
@@ -72,10 +92,32 @@ namespace keepass2android
public bool SetText (string strNewText, LogStatusType lsType)
{
- UpdateMessage(strNewText);
+ if (strNewText.StartsWith("KP2AKEY_"))
+ {
+ UiStringKey key;
+ if (Enum.TryParse(strNewText.Substring("KP2AKEY_".Length), true, out key))
+ {
+ UpdateMessage(_app.GetResourceString(key), lsType);
+ return true;
+ }
+ }
+ UpdateMessage(strNewText, lsType);
+
return true;
}
+ private void UpdateMessage(string message, LogStatusType lsType)
+ {
+ if (lsType == LogStatusType.AdditionalInfo)
+ {
+ UpdateSubMessage(message);
+ }
+ else
+ {
+ UpdateMessage(message);
+ }
+ }
+
public bool ContinueWork ()
{
return true;
diff --git a/src/Kp2aBusinessLogic/ProgressTask.cs b/src/Kp2aBusinessLogic/ProgressTask.cs
index 71e5369f..b26fc667 100644
--- a/src/Kp2aBusinessLogic/ProgressTask.cs
+++ b/src/Kp2aBusinessLogic/ProgressTask.cs
@@ -32,7 +32,7 @@ namespace keepass2android
private readonly IKp2aApp _app;
private Thread _thread;
- public ProgressTask(IKp2aApp app, Context ctx, RunnableOnFinish task, UiStringKey messageKey) {
+ public ProgressTask(IKp2aApp app, Context ctx, RunnableOnFinish task) {
_task = task;
_handler = app.UiThreadHandler;
_app = app;
@@ -40,11 +40,12 @@ namespace keepass2android
// Show process dialog
_progressDialog = app.CreateProgressDialog(ctx);
_progressDialog.SetTitle(_app.GetResourceString(UiStringKey.progress_title));
- _progressDialog.SetMessage(_app.GetResourceString(messageKey));
+ _progressDialog.SetMessage("Initializing...");
// Set code to run when this is finished
- _task.SetStatus(new UpdateStatus(_app, _handler, _progressDialog));
_task.OnFinishToRun = new AfterTask(task.OnFinishToRun, _handler, _progressDialog);
+ _task.SetStatusLogger(new ProgressDialogStatusLogger(_app, _handler, _progressDialog));
+
}
diff --git a/src/Kp2aBusinessLogic/UiStringKey.cs b/src/Kp2aBusinessLogic/UiStringKey.cs
index fd6982c0..534bc637 100644
--- a/src/Kp2aBusinessLogic/UiStringKey.cs
+++ b/src/Kp2aBusinessLogic/UiStringKey.cs
@@ -17,6 +17,19 @@ namespace keepass2android
keyfile_does_not_exist,
RecycleBin,
progress_create,
- loading_database
+ loading_database,
+ AddingEntry,
+ AddingGroup,
+ DeletingEntry,
+ DeletingGroup,
+ SettingPassword,
+ UndoingChanges,
+ TransformingKey,
+ DecodingDatabase,
+ ParsingDatabase,
+ CheckingTargetFileForChanges,
+ TitleSyncQuestion,
+ MessageSyncQuestions,
+ SynchronizingDatabase
}
}
\ No newline at end of file
diff --git a/src/Kp2aBusinessLogic/database/Database.cs b/src/Kp2aBusinessLogic/database/Database.cs
index 99ea6ad9..a5cdf677 100644
--- a/src/Kp2aBusinessLogic/database/Database.cs
+++ b/src/Kp2aBusinessLogic/database/Database.cs
@@ -17,10 +17,12 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
using System;
using System.Collections.Generic;
+using System.IO;
using Android.Content;
using KeePassLib;
using KeePassLib.Keys;
using KeePassLib.Serialization;
+using keepass2android.Io;
namespace keepass2android
{
@@ -34,7 +36,7 @@ namespace keepass2android
public PwGroup Root;
public PwDatabase KpDatabase;
public IOConnectionInfo Ioc { get { return KpDatabase.IOConnectionInfo; } }
- public DateTime LastChangeDate;
+ public string LastFileVersion;
public SearchDbHelper SearchHelper;
public IDrawableFactory DrawableFactory;
@@ -83,15 +85,16 @@ namespace keepass2android
public bool DidOpenFileChange()
{
- if ((Loaded == false) || (Ioc.IsLocalFile() == false))
+ if (Loaded == false)
{
return false;
}
- return System.IO.File.GetLastWriteTimeUtc(Ioc.Path) > LastChangeDate;
+ return _app.GetFileStorage(Ioc).CheckForFileChangeFast(Ioc, LastFileVersion);
+
}
- public void LoadData(IKp2aApp app, IOConnectionInfo iocInfo, String password, String keyfile, UpdateStatus status)
+ public void LoadData(IKp2aApp app, IOConnectionInfo iocInfo, String password, String keyfile, ProgressDialogStatusLogger status)
{
PwDatabase pwDatabase = new PwDatabase();
@@ -103,15 +106,17 @@ namespace keepass2android
try
{
compositeKey.AddUserKey(new KcpKeyFile(keyfile));
- } catch (Exception)
+ } catch (Exception e)
{
+ Kp2aLog.Log(e.ToString());
throw new KeyFileException();
}
}
try
{
- pwDatabase.Open(iocInfo, compositeKey, status);
+ IFileStorage fileStorage = _app.GetFileStorage(iocInfo);
+ pwDatabase.Open(fileStorage.OpenFileForRead(iocInfo), fileStorage.GetFilenameWithoutPathAndExt(iocInfo), iocInfo, compositeKey, status);
}
catch (Exception)
{
@@ -125,14 +130,9 @@ namespace keepass2android
else throw;
}
+ status.UpdateSubMessage("");
- if (iocInfo.IsLocalFile())
- {
- LastChangeDate = System.IO.File.GetLastWriteTimeUtc(iocInfo.Path);
- } else
- {
- LastChangeDate = DateTime.MinValue;
- }
+ LastFileVersion = _app.GetFileStorage(iocInfo).GetCurrentFileVersionFast(iocInfo);
Root = pwDatabase.RootGroup;
PopulateGlobals(Root);
@@ -184,9 +184,14 @@ namespace keepass2android
public void SaveData(Context ctx) {
KpDatabase.UseFileTransactions = _app.GetBooleanPreference(PreferenceKey.UseFileTransactions);
- KpDatabase.Save(null);
-
+ using (IWriteTransaction trans = _app.GetFileStorage(Ioc).OpenWriteTransaction(Ioc, KpDatabase.UseFileTransactions))
+ {
+ KpDatabase.Save(trans.OpenFile(), null);
+ trans.CommitWrite();
+ }
+
}
+
private void PopulateGlobals (PwGroup currentGroup)
{
diff --git a/src/Kp2aBusinessLogic/database/edit/AddEntry.cs b/src/Kp2aBusinessLogic/database/edit/AddEntry.cs
index 1de447c1..4db60b9a 100644
--- a/src/Kp2aBusinessLogic/database/edit/AddEntry.cs
+++ b/src/Kp2aBusinessLogic/database/edit/AddEntry.cs
@@ -21,31 +21,38 @@ using KeePassLib;
namespace keepass2android
{
public class AddEntry : RunnableOnFinish {
- protected Database Db;
+ protected Database Db
+ {
+ get { return _app.GetDb(); }
+ }
+
+ private readonly IKp2aApp _app;
private readonly PwEntry _entry;
private readonly PwGroup _parentGroup;
private readonly Context _ctx;
- public static AddEntry GetInstance(Context ctx, Database db, PwEntry entry, PwGroup parentGroup, OnFinish finish) {
+ public static AddEntry GetInstance(Context ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish) {
- return new AddEntry(ctx, db, entry, parentGroup, finish);
+ return new AddEntry(ctx, app, entry, parentGroup, finish);
}
- protected AddEntry(Context ctx, Database db, PwEntry entry, PwGroup parentGroup, OnFinish finish):base(finish) {
+ protected AddEntry(Context ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish):base(finish) {
_ctx = ctx;
_parentGroup = parentGroup;
- Db = db;
+ _app = app;
_entry = entry;
- OnFinishToRun = new AfterAdd(db, entry, OnFinishToRun);
+ _onFinishToRun = new AfterAdd(app.GetDb(), entry, OnFinishToRun);
}
- public override void Run() {
+ public override void Run() {
+ StatusLogger.UpdateMessage(UiStringKey.AddingEntry);
_parentGroup.AddEntry(_entry, true);
// Commit to disk
- SaveDb save = new SaveDb(_ctx, Db, OnFinishToRun);
+ SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun);
+ save.SetStatusLogger(StatusLogger);
save.Run();
}
@@ -72,7 +79,9 @@ namespace keepass2android
// Add entry to global
_db.Entries[_entry.Uuid] = _entry;
- } else {
+ } else
+ {
+ StatusLogger.UpdateMessage(UiStringKey.UndoingChanges);
//TODO test fail
_entry.ParentGroup.Entries.Remove(_entry);
}
diff --git a/src/Kp2aBusinessLogic/database/edit/AddGroup.cs b/src/Kp2aBusinessLogic/database/edit/AddGroup.cs
index b972dd97..92b72b19 100644
--- a/src/Kp2aBusinessLogic/database/edit/AddGroup.cs
+++ b/src/Kp2aBusinessLogic/database/edit/AddGroup.cs
@@ -23,7 +23,11 @@ namespace keepass2android
{
public class AddGroup : RunnableOnFinish {
- internal Database Db;
+ internal Database Db
+ {
+ get { return _app.GetDb(); }
+ }
+ private IKp2aApp _app;
private readonly String _name;
private readonly int _iconId;
internal PwGroup Group;
@@ -32,31 +36,32 @@ namespace keepass2android
readonly Context _ctx;
- public static AddGroup GetInstance(Context ctx, Database db, String name, int iconid, PwGroup parent, OnFinish finish, bool dontSave) {
- return new AddGroup(ctx, db, name, iconid, parent, finish, dontSave);
+ public static AddGroup GetInstance(Context ctx, IKp2aApp app, String name, int iconid, PwGroup parent, OnFinish finish, bool dontSave) {
+ return new AddGroup(ctx, app, name, iconid, parent, finish, dontSave);
}
- private AddGroup(Context ctx, Database db, String name, int iconid, PwGroup parent, OnFinish finish, bool dontSave): base(finish) {
+ private AddGroup(Context ctx, IKp2aApp app, String name, int iconid, PwGroup parent, OnFinish finish, bool dontSave): base(finish) {
_ctx = ctx;
- Db = db;
_name = name;
_iconId = iconid;
Parent = parent;
DontSave = dontSave;
-
- OnFinishToRun = new AfterAdd(this, OnFinishToRun);
+ _app = app;
+
+ _onFinishToRun = new AfterAdd(this, OnFinishToRun);
}
public override void Run() {
-
+ StatusLogger.UpdateMessage(UiStringKey.AddingGroup);
// Generate new group
Group = new PwGroup(true, true, _name, (PwIcon)_iconId);
Parent.AddGroup(Group, true);
// Commit to disk
- SaveDb save = new SaveDb(_ctx, Db, OnFinishToRun, DontSave);
+ SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, DontSave);
+ save.SetStatusLogger(StatusLogger);
save.Run();
}
@@ -77,6 +82,7 @@ namespace keepass2android
// Add group to global list
_addGroup.Db.Groups[_addGroup.Group.Uuid] = _addGroup.Group;
} else {
+ StatusLogger.UpdateMessage(UiStringKey.UndoingChanges);
_addGroup.Parent.Groups.Remove(_addGroup.Group);
}
diff --git a/src/Kp2aBusinessLogic/database/edit/CreateDB.cs b/src/Kp2aBusinessLogic/database/edit/CreateDB.cs
index 51efa761..ce883733 100644
--- a/src/Kp2aBusinessLogic/database/edit/CreateDB.cs
+++ b/src/Kp2aBusinessLogic/database/edit/CreateDB.cs
@@ -40,6 +40,7 @@ namespace keepass2android
public override void Run() {
+ StatusLogger.UpdateMessage(UiStringKey.progress_create);
Database db = _app.CreateNewDatabase();
db.KpDatabase = new KeePassLib.PwDatabase();
@@ -58,14 +59,15 @@ namespace keepass2android
db.SearchHelper = new SearchDbHelper(_app);
// Add a couple default groups
- AddGroup internet = AddGroup.GetInstance(_ctx, db, "Internet", 1, db.KpDatabase.RootGroup, null, true);
+ AddGroup internet = AddGroup.GetInstance(_ctx, _app, "Internet", 1, db.KpDatabase.RootGroup, null, true);
internet.Run();
- AddGroup email = AddGroup.GetInstance(_ctx, db, "eMail", 19, db.KpDatabase.RootGroup, null, true);
+ AddGroup email = AddGroup.GetInstance(_ctx, _app, "eMail", 19, db.KpDatabase.RootGroup, null, true);
email.Run();
// Commit changes
- SaveDb save = new SaveDb(_ctx, db, OnFinishToRun, _dontSave);
- OnFinishToRun = null;
+ SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, _dontSave);
+ save.SetStatusLogger(StatusLogger);
+ _onFinishToRun = null;
save.Run();
diff --git a/src/Kp2aBusinessLogic/database/edit/DeleteEntry.cs b/src/Kp2aBusinessLogic/database/edit/DeleteEntry.cs
index 97a468e4..9ba8c469 100644
--- a/src/Kp2aBusinessLogic/database/edit/DeleteEntry.cs
+++ b/src/Kp2aBusinessLogic/database/edit/DeleteEntry.cs
@@ -48,8 +48,9 @@ namespace keepass2android
}
}
- public override void Run() {
-
+ public override void Run()
+ {
+ StatusLogger.UpdateMessage(UiStringKey.DeletingEntry);
PwDatabase pd = Db.KpDatabase;
PwGroup pgRecycleBin = pd.RootGroup.FindGroup(pd.RecycleBinUuid, true);
@@ -68,7 +69,7 @@ namespace keepass2android
PwDeletedObject pdo = new PwDeletedObject(pe.Uuid, dtNow);
pd.DeletedObjects.Add(pdo);
- OnFinishToRun = new ActionOnFinish((success, message) =>
+ _onFinishToRun = new ActionOnFinish((success, message) =>
{
if (success)
{
@@ -89,7 +90,7 @@ namespace keepass2android
pgRecycleBin.AddEntry(pe, true, true);
pe.Touch(false);
- OnFinishToRun = new ActionOnFinish( (success, message) =>
+ _onFinishToRun = new ActionOnFinish( (success, message) =>
{
if ( success ) {
// Mark previous parent dirty
@@ -106,7 +107,8 @@ namespace keepass2android
}
// Commit database
- SaveDb save = new SaveDb(Ctx, Db, OnFinishToRun, false);
+ SaveDb save = new SaveDb(Ctx, App, OnFinishToRun, false);
+ save.SetStatusLogger(StatusLogger);
save.Run();
diff --git a/src/Kp2aBusinessLogic/database/edit/DeleteGroup.cs b/src/Kp2aBusinessLogic/database/edit/DeleteGroup.cs
index 8c7bd71a..1586b0df 100644
--- a/src/Kp2aBusinessLogic/database/edit/DeleteGroup.cs
+++ b/src/Kp2aBusinessLogic/database/edit/DeleteGroup.cs
@@ -70,6 +70,7 @@ namespace keepass2android
public override void Run() {
+ StatusLogger.UpdateMessage(UiStringKey.DeletingGroup);
//from KP Desktop
PwGroup pg = _group;
PwGroup pgParent = pg.ParentGroup;
@@ -86,7 +87,7 @@ namespace keepass2android
PwDeletedObject pdo = new PwDeletedObject(pg.Uuid, DateTime.Now);
pd.DeletedObjects.Add(pdo);
- OnFinishToRun = new AfterDeletePermanently(OnFinishToRun, App, _group);
+ _onFinishToRun = new AfterDeletePermanently(OnFinishToRun, App, _group);
}
else // Recycle
{
@@ -95,7 +96,7 @@ namespace keepass2android
pgRecycleBin.AddGroup(pg, true, true);
pg.Touch(false);
- OnFinishToRun = new ActionOnFinish((success, message) =>
+ _onFinishToRun = new ActionOnFinish((success, message) =>
{
if ( success ) {
// Mark new parent (Recycle bin) dirty
@@ -113,7 +114,8 @@ namespace keepass2android
}
// Save
- SaveDb save = new SaveDb(Ctx, Db, OnFinishToRun, DontSave);
+ SaveDb save = new SaveDb(Ctx, App, OnFinishToRun, DontSave);
+ save.SetStatusLogger(StatusLogger);
save.Run();
}
diff --git a/src/Kp2aBusinessLogic/database/edit/DeleteRunnable.cs b/src/Kp2aBusinessLogic/database/edit/DeleteRunnable.cs
index 3b07a551..cab35523 100644
--- a/src/Kp2aBusinessLogic/database/edit/DeleteRunnable.cs
+++ b/src/Kp2aBusinessLogic/database/edit/DeleteRunnable.cs
@@ -109,12 +109,12 @@ namespace keepass2android
(dlgSender, dlgEvt) =>
{
DeletePermanently = true;
- ProgressTask pt = new ProgressTask(App, Ctx, this, UiStringKey.saving_database);
+ ProgressTask pt = new ProgressTask(App, Ctx, this);
pt.Run();
},
(dlgSender, dlgEvt) => {
DeletePermanently = false;
- ProgressTask pt = new ProgressTask(App, Ctx, this, UiStringKey.saving_database);
+ ProgressTask pt = new ProgressTask(App, Ctx, this);
pt.Run();
},
(dlgSender, dlgEvt) => {},
@@ -124,7 +124,7 @@ namespace keepass2android
} else
{
- ProgressTask pt = new ProgressTask(App, Ctx, this, UiStringKey.saving_database);
+ ProgressTask pt = new ProgressTask(App, Ctx, this);
pt.Run();
}
}
diff --git a/src/Kp2aBusinessLogic/database/edit/LoadDB.cs b/src/Kp2aBusinessLogic/database/edit/LoadDB.cs
index 378a4614..239c04a9 100644
--- a/src/Kp2aBusinessLogic/database/edit/LoadDB.cs
+++ b/src/Kp2aBusinessLogic/database/edit/LoadDB.cs
@@ -43,7 +43,8 @@ namespace keepass2android
{
try
{
- _app.GetDb().LoadData (_app, _ioc, _pass, _key, Status);
+ StatusLogger.UpdateMessage(UiStringKey.loading_database);
+ _app.GetDb().LoadData (_app, _ioc, _pass, _key, StatusLogger);
SaveFileData (_ioc, _key);
} catch (KeyFileException) {
diff --git a/src/Kp2aBusinessLogic/database/edit/OnFinish.cs b/src/Kp2aBusinessLogic/database/edit/OnFinish.cs
index 8fd26f4f..a23926a0 100644
--- a/src/Kp2aBusinessLogic/database/edit/OnFinish.cs
+++ b/src/Kp2aBusinessLogic/database/edit/OnFinish.cs
@@ -29,6 +29,13 @@ namespace keepass2android
protected OnFinish BaseOnFinish;
protected Handler Handler;
+ private ProgressDialogStatusLogger _statusLogger = new ProgressDialogStatusLogger(); //default: no logging but not null -> can be used whenever desired
+
+ public ProgressDialogStatusLogger StatusLogger
+ {
+ get { return _statusLogger; }
+ set { _statusLogger = value; }
+ }
protected OnFinish() {
}
@@ -47,7 +54,7 @@ namespace keepass2android
BaseOnFinish = finish;
Handler = null;
}
-
+
public void SetResult(bool success, String message) {
Success = success;
Message = message;
diff --git a/src/Kp2aBusinessLogic/database/edit/RunnableOnFinish.cs b/src/Kp2aBusinessLogic/database/edit/RunnableOnFinish.cs
index f899519c..6a5e4da5 100644
--- a/src/Kp2aBusinessLogic/database/edit/RunnableOnFinish.cs
+++ b/src/Kp2aBusinessLogic/database/edit/RunnableOnFinish.cs
@@ -21,13 +21,19 @@ namespace keepass2android
public abstract class RunnableOnFinish {
- public OnFinish OnFinishToRun;
- public UpdateStatus Status;
+ protected OnFinish _onFinishToRun;
+ public ProgressDialogStatusLogger StatusLogger = new ProgressDialogStatusLogger(); //default: empty but not null
protected RunnableOnFinish(OnFinish finish) {
- OnFinishToRun = finish;
+ _onFinishToRun = finish;
}
-
+
+ public OnFinish OnFinishToRun
+ {
+ get { return _onFinishToRun; }
+ set { _onFinishToRun = value; }
+ }
+
protected void Finish(bool result, String message) {
if ( OnFinishToRun != null ) {
OnFinishToRun.SetResult(result, message);
@@ -42,8 +48,12 @@ namespace keepass2android
}
}
- public void SetStatus(UpdateStatus status) {
- Status = status;
+ public void SetStatusLogger(ProgressDialogStatusLogger status) {
+ if (OnFinishToRun != null)
+ {
+ OnFinishToRun.StatusLogger = status;
+ }
+ StatusLogger = status;
}
abstract public void Run();
diff --git a/src/Kp2aBusinessLogic/database/edit/SaveDB.cs b/src/Kp2aBusinessLogic/database/edit/SaveDB.cs
index c98fe438..a3b76089 100644
--- a/src/Kp2aBusinessLogic/database/edit/SaveDB.cs
+++ b/src/Kp2aBusinessLogic/database/edit/SaveDB.cs
@@ -14,26 +14,40 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see .
*/
+
using System;
+using System.IO;
+using System.Security.Cryptography;
using Android.Content;
+using Android.OS;
+using Java.Lang;
+using KeePassLib;
+using KeePassLib.Serialization;
+using KeePassLib.Utility;
+using keepass2android.Io;
+using Debug = System.Diagnostics.Debug;
+using Exception = System.Exception;
namespace keepass2android
{
public class SaveDb : RunnableOnFinish {
- private readonly Database _db;
+ private readonly IKp2aApp _app;
private readonly bool _dontSave;
private readonly Context _ctx;
-
- public SaveDb(Context ctx, Database db, OnFinish finish, bool dontSave): base(finish) {
+ private Thread _workerThread;
+
+ public SaveDb(Context ctx, IKp2aApp app, OnFinish finish, bool dontSave): base(finish) {
_ctx = ctx;
- _db = db;
+ _app = app;
_dontSave = dontSave;
}
- public SaveDb(Context ctx, Database db, OnFinish finish):base(finish) {
+ public SaveDb(Context ctx, IKp2aApp app, OnFinish finish)
+ : base(finish)
+ {
_ctx = ctx;
- _db = db;
+ _app = app;
_dontSave = false;
}
@@ -42,10 +56,67 @@ namespace keepass2android
{
if (! _dontSave) {
- try {
- _db.SaveData (_ctx);
- if (_db.Ioc.IsLocalFile())
- _db.LastChangeDate = System.IO.File.GetLastWriteTimeUtc(_db.Ioc.Path);
+ try
+ {
+ StatusLogger.UpdateMessage(UiStringKey.saving_database);
+ IOConnectionInfo ioc = _app.GetDb().Ioc;
+ IFileStorage fileStorage = _app.GetFileStorage(ioc);
+
+ if ((!_app.GetBooleanPreference(PreferenceKey.CheckForFileChangesOnSave))
+ || (_app.GetDb().KpDatabase.HashOfFileOnDisk == null)) //first time saving
+ {
+ PerformSaveWithoutCheck(fileStorage, ioc);
+ Finish(true);
+ return;
+ }
+
+
+
+ if (fileStorage.CheckForFileChangeFast(ioc, _app.GetDb().LastFileVersion) //first try to use the fast change detection
+ || (FileHashChanged(ioc, _app.GetDb().KpDatabase.HashOfFileOnDisk))) //if that fails, hash the file and compare:
+ {
+ //ask user...
+ _app.AskYesNoCancel(UiStringKey.TitleSyncQuestion, UiStringKey.MessageSyncQuestions,
+ //yes = sync
+ (sender, args) =>
+ {
+ Action runHandler = () =>
+ {
+ //note: when synced, the file might be downloaded once again from the server. Caching the data
+ //in the hashing function would solve this but increases complexity. I currently assume the files are
+ //small.
+ StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.SynchronizingDatabase));
+ MergeIn(fileStorage, ioc);
+ PerformSaveWithoutCheck(fileStorage, ioc);
+ Finish(true);
+ };
+ RunInWorkerThread(runHandler);
+ },
+ //no = overwrite
+ (sender, args) =>
+ {
+ RunInWorkerThread( () =>
+ {
+ PerformSaveWithoutCheck(fileStorage, ioc);
+ Finish(true);
+ });
+ },
+ //cancel
+ (sender, args) =>
+ {
+ RunInWorkerThread(() => Finish(false));
+ },
+ _ctx
+ );
+
+
+ }
+ else
+ {
+ PerformSaveWithoutCheck(fileStorage, ioc);
+ Finish(true);
+ }
+
} catch (Exception e) {
/* TODO KPDesktop:
* catch(Exception exSave)
@@ -54,13 +125,85 @@ namespace keepass2android
bSuccess = false;
}
*/
- Finish (false, e.Message);
+ Finish (false, e.ToString());
return;
}
}
- Finish(true);
+
}
+
+ private void RunInWorkerThread(Action runHandler)
+ {
+ try
+ {
+ _workerThread = new Thread(runHandler);
+ _workerThread.Run();
+ }
+ catch (Exception e)
+ {
+ Kp2aLog.Log("Error in worker thread of SaveDb: "+e);
+ Finish(false, e.Message);
+ }
+
+ }
+
+ public void JoinWorkerThread()
+ {
+ if (_workerThread != null)
+ _workerThread.Join();
+ }
+
+ private void MergeIn(IFileStorage fileStorage, IOConnectionInfo ioc)
+ {
+ PwDatabase pwImp = new PwDatabase();
+ PwDatabase pwDatabase = _app.GetDb().KpDatabase;
+ pwImp.New(new IOConnectionInfo(), pwDatabase.MasterKey);
+ pwImp.MemoryProtection = pwDatabase.MemoryProtection.CloneDeep();
+ pwImp.MasterKey = pwDatabase.MasterKey;
+ KdbxFile kdbx = new KdbxFile(pwImp);
+ kdbx.Load(fileStorage.OpenFileForRead(ioc), KdbxFormat.Default, null);
+
+ pwDatabase.MergeIn(pwImp, PwMergeMethod.Synchronize, null);
+
+ }
+
+ private void PerformSaveWithoutCheck(IFileStorage fileStorage, IOConnectionInfo ioc)
+ {
+ _app.GetDb().SaveData(_ctx);
+ _app.GetDb().LastFileVersion = fileStorage.GetCurrentFileVersionFast(ioc);
+ }
+
+ public byte[] HashFile(IOConnectionInfo iocFile)
+ {
+ if (iocFile == null) { Debug.Assert(false); return null; } // Assert only
+
+ Stream sIn;
+ try
+ {
+ sIn = _app.GetFileStorage(iocFile).OpenFileForRead(iocFile);
+ if (sIn == null) throw new FileNotFoundException();
+ }
+ catch (Exception) { return null; }
+
+ byte[] pbHash;
+ try
+ {
+ SHA256Managed sha256 = new SHA256Managed();
+ pbHash = sha256.ComputeHash(sIn);
+ }
+ catch (Exception) { Debug.Assert(false); sIn.Close(); return null; }
+
+ sIn.Close();
+ return pbHash;
+ }
+
+ private bool FileHashChanged(IOConnectionInfo ioc, byte[] hashOfFileOnDisk)
+ {
+ StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.CheckingTargetFileForChanges));
+ return !MemUtil.ArraysEqual(HashFile(ioc), hashOfFileOnDisk);
+ }
+
}
diff --git a/src/Kp2aBusinessLogic/database/edit/SetPassword.cs b/src/Kp2aBusinessLogic/database/edit/SetPassword.cs
index ca238321..521414c3 100644
--- a/src/Kp2aBusinessLogic/database/edit/SetPassword.cs
+++ b/src/Kp2aBusinessLogic/database/edit/SetPassword.cs
@@ -25,21 +25,23 @@ namespace keepass2android
private readonly String _password;
private readonly String _keyfile;
- private readonly Database _db;
+ private readonly IKp2aApp _app;
private readonly bool _dontSave;
private readonly Context _ctx;
- public SetPassword(Context ctx, Database db, String password, String keyfile, OnFinish finish): base(finish) {
+ public SetPassword(Context ctx, IKp2aApp app, String password, String keyfile, OnFinish finish): base(finish) {
_ctx = ctx;
- _db = db;
+ _app = app;
_password = password;
_keyfile = keyfile;
_dontSave = false;
}
-
- public SetPassword(Context ctx, Database db, String password, String keyfile, OnFinish finish, bool dontSave): base(finish) {
+
+ public SetPassword(Context ctx, IKp2aApp app, String password, String keyfile, OnFinish finish, bool dontSave)
+ : base(finish)
+ {
_ctx = ctx;
- _db = db;
+ _app = app;
_password = password;
_keyfile = keyfile;
_dontSave = dontSave;
@@ -48,7 +50,8 @@ namespace keepass2android
public override void Run ()
{
- PwDatabase pm = _db.KpDatabase;
+ StatusLogger.UpdateMessage(UiStringKey.SettingPassword);
+ PwDatabase pm = _app.GetDb().KpDatabase;
CompositeKey newKey = new CompositeKey ();
if (String.IsNullOrEmpty (_password) == false) {
newKey.AddUserKey (new KcpPassword (_password));
@@ -69,8 +72,9 @@ namespace keepass2android
pm.MasterKey = newKey;
// Save Database
- OnFinishToRun = new AfterSave(previousKey, previousMasterKeyChanged, pm, OnFinishToRun);
- SaveDb save = new SaveDb(_ctx, _db, OnFinishToRun, _dontSave);
+ _onFinishToRun = new AfterSave(previousKey, previousMasterKeyChanged, pm, OnFinishToRun);
+ SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, _dontSave);
+ save.SetStatusLogger(StatusLogger);
save.Run();
}
diff --git a/src/Kp2aBusinessLogic/database/edit/UpdateEntry.cs b/src/Kp2aBusinessLogic/database/edit/UpdateEntry.cs
index 40f7bf4a..b4850566 100644
--- a/src/Kp2aBusinessLogic/database/edit/UpdateEntry.cs
+++ b/src/Kp2aBusinessLogic/database/edit/UpdateEntry.cs
@@ -22,32 +22,33 @@ namespace keepass2android
{
public class UpdateEntry : RunnableOnFinish {
- private readonly Database _db;
+ private readonly IKp2aApp _app;
private readonly Context _ctx;
- public UpdateEntry(Context ctx, Database db, PwEntry oldE, PwEntry newE, OnFinish finish):base(finish) {
+ public UpdateEntry(Context ctx, IKp2aApp app, PwEntry oldE, PwEntry newE, OnFinish finish):base(finish) {
_ctx = ctx;
- _db = db;
+ _app = app;
- OnFinishToRun = new AfterUpdate(oldE, newE, db, finish);
+ _onFinishToRun = new AfterUpdate(oldE, newE, app, finish);
}
public override void Run() {
// Commit to disk
- SaveDb save = new SaveDb(_ctx, _db, OnFinishToRun);
+ SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun);
+ save.SetStatusLogger(StatusLogger);
save.Run();
}
private class AfterUpdate : OnFinish {
private readonly PwEntry _backup;
private readonly PwEntry _updatedEntry;
- private readonly Database _db;
+ private readonly IKp2aApp _app;
- public AfterUpdate(PwEntry backup, PwEntry updatedEntry, Database db, OnFinish finish):base(finish) {
+ public AfterUpdate(PwEntry backup, PwEntry updatedEntry, IKp2aApp app, OnFinish finish):base(finish) {
_backup = backup;
_updatedEntry = updatedEntry;
- _db = db;
+ _app = app;
}
public override void Run() {
@@ -65,11 +66,12 @@ namespace keepass2android
if ( parent != null ) {
// Mark parent group dirty
- _db.Dirty.Add(parent);
+ _app.GetDb().Dirty.Add(parent);
}
}
} else {
+ StatusLogger.UpdateMessage(UiStringKey.UndoingChanges);
// If we fail to save, back out changes to global structure
//TODO test fail
_updatedEntry.AssignProperties(_backup, false, true, false);
diff --git a/src/Kp2aUnitTests/MainActivity.cs b/src/Kp2aUnitTests/MainActivity.cs
index e67cbb0b..d1370c27 100644
--- a/src/Kp2aUnitTests/MainActivity.cs
+++ b/src/Kp2aUnitTests/MainActivity.cs
@@ -20,7 +20,8 @@ namespace Kp2aUnitTests
// Run all tests from this assembly
runner.AddTests(Assembly.GetExecutingAssembly());
//runner.AddTests(new List { typeof(TestSaveDb)});
- //runner.AddTests(typeof(TestLoadDb).GetMethod("TestLoadWithPasswordOnly"));}}
+ //runner.AddTests(typeof(TestSaveDb).GetMethod("TestLoadEditSaveWithSyncConflict"));
+ //runner.AddTests(typeof(TestSaveDb).GetMethod("TestLoadEditSave"));
return runner;
}
}
diff --git a/src/Kp2aUnitTests/ProgressDialogStub.cs b/src/Kp2aUnitTests/ProgressDialogStub.cs
index ef68a6c5..e31fee1d 100644
--- a/src/Kp2aUnitTests/ProgressDialogStub.cs
+++ b/src/Kp2aUnitTests/ProgressDialogStub.cs
@@ -12,9 +12,9 @@ namespace Kp2aUnitTests
}
- public void SetMessage(string getResourceString)
+ public void SetMessage(string resourceString)
{
-
+ Kp2aLog.Log("Progress message: " + resourceString);
}
public void Dismiss()
diff --git a/src/Kp2aUnitTests/TestBase.cs b/src/Kp2aUnitTests/TestBase.cs
index 8e7f9340..328fa767 100644
--- a/src/Kp2aUnitTests/TestBase.cs
+++ b/src/Kp2aUnitTests/TestBase.cs
@@ -74,7 +74,7 @@ namespace Kp2aUnitTests
})
);
- ProgressTask pt = new ProgressTask(app, Application.Context, task, UiStringKey.loading_database);
+ ProgressTask pt = new ProgressTask(app, Application.Context, task);
pt.Run();
pt.JoinWorkerThread();
Assert.IsTrue(loadSuccesful);
@@ -83,16 +83,27 @@ namespace Kp2aUnitTests
protected void SaveDatabase(IKp2aApp app)
{
- bool saveSuccesful = false;
- SaveDb save = new SaveDb(Application.Context, app.GetDb(), new ActionOnFinish((success, message) =>
- {
- saveSuccesful = success;
- }), false);
- save.Run();
+ bool saveSuccesful = TrySaveDatabase(app);
Assert.IsTrue(saveSuccesful);
}
+ public static bool TrySaveDatabase(IKp2aApp app)
+ {
+ bool saveSuccesful = false;
+ SaveDb save = new SaveDb(Application.Context, app, new ActionOnFinish((success, message) =>
+ {
+ saveSuccesful = success;
+ if (!success)
+ {
+ Kp2aLog.Log("Error during TestBase.SaveDatabase: " + message);
+ }
+ }), false);
+ save.Run();
+ save.JoinWorkerThread();
+ return saveSuccesful;
+ }
+
protected IKp2aApp SetupAppWithDefaultDatabase()
{
IKp2aApp app = new TestKp2aApp();
diff --git a/src/Kp2aUnitTests/TestKp2aApp.cs b/src/Kp2aUnitTests/TestKp2aApp.cs
index 88fab8a3..365a9355 100644
--- a/src/Kp2aUnitTests/TestKp2aApp.cs
+++ b/src/Kp2aUnitTests/TestKp2aApp.cs
@@ -1,8 +1,10 @@
using System;
+using System.Collections.Generic;
using Android.Content;
using Android.OS;
using KeePassLib.Serialization;
using keepass2android;
+using keepass2android.Io;
namespace Kp2aUnitTests
{
@@ -11,7 +13,14 @@ namespace Kp2aUnitTests
///
internal class TestKp2aApp : IKp2aApp
{
+ internal enum YesNoCancelResult
+ {
+ Yes, No, Cancel
+ }
+
private Database _db;
+ private YesNoCancelResult _yesNoCancelResult = YesNoCancelResult.Yes;
+ private Dictionary _preferences = new Dictionary();
public void SetShutdown()
{
@@ -43,13 +52,32 @@ namespace Kp2aUnitTests
public bool GetBooleanPreference(PreferenceKey key)
{
+ if (_preferences.ContainsKey(key))
+ return _preferences[key];
return true;
}
+ public UiStringKey? LastYesNoCancelQuestionTitle { get; set; }
+
public void AskYesNoCancel(UiStringKey titleKey, UiStringKey messageKey, EventHandler yesHandler, EventHandler noHandler,
EventHandler cancelHandler, Context ctx)
{
- yesHandler(null, null);
+ LastYesNoCancelQuestionTitle = titleKey;
+ switch (_yesNoCancelResult)
+ {
+ case YesNoCancelResult.Yes:
+ yesHandler(null, null);
+ break;
+ case YesNoCancelResult.No:
+ noHandler(null, null);
+ break;
+ case YesNoCancelResult.Cancel:
+ cancelHandler(null, null);
+ break;
+ default:
+ throw new Exception("unexpected case!");
+ }
+
}
public Handler UiThreadHandler {
@@ -59,5 +87,20 @@ namespace Kp2aUnitTests
{
return new ProgressDialogStub();
}
+
+ public IFileStorage GetFileStorage(IOConnectionInfo iocInfo)
+ {
+ return new BuiltInFileStorage();
+ }
+
+ public void SetYesNoCancelResult(YesNoCancelResult yesNoCancelResult)
+ {
+ _yesNoCancelResult = yesNoCancelResult;
+ }
+
+ public void SetPreference(PreferenceKey key, bool value)
+ {
+ _preferences[key] = value;
+ }
}
}
\ No newline at end of file
diff --git a/src/Kp2aUnitTests/TestLoadDb.cs b/src/Kp2aUnitTests/TestLoadDb.cs
index 96f4d2c3..d7e2402b 100644
--- a/src/Kp2aUnitTests/TestLoadDb.cs
+++ b/src/Kp2aUnitTests/TestLoadDb.cs
@@ -26,7 +26,7 @@ namespace Kp2aUnitTests
loadSuccesful = success;
})
);
- ProgressTask pt = new ProgressTask(app, Application.Context, task, UiStringKey.loading_database);
+ ProgressTask pt = new ProgressTask(app, Application.Context, task);
Android.Util.Log.Debug("KP2ATest", "Running ProgressTask");
pt.Run();
pt.JoinWorkerThread();
diff --git a/src/Kp2aUnitTests/TestSaveDb.cs b/src/Kp2aUnitTests/TestSaveDb.cs
index a07eb665..58c704d9 100644
--- a/src/Kp2aUnitTests/TestSaveDb.cs
+++ b/src/Kp2aUnitTests/TestSaveDb.cs
@@ -1,11 +1,13 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Android.App;
using Android.OS;
using KeePassLib;
+using KeePassLib.Keys;
using KeePassLib.Serialization;
using KeePassLib.Utility;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -23,6 +25,7 @@ namespace Kp2aUnitTests
{
//create the default database:
IKp2aApp app = SetupAppWithDefaultDatabase();
+ IOConnection.DeleteFile(new IOConnectionInfo { Path = DefaultFilename });
//save it and reload it so we have a base version
SaveDatabase(app);
app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
@@ -56,9 +59,14 @@ namespace Kp2aUnitTests
//save the database from app 1:
SaveDatabase(app);
+ ((TestKp2aApp)app2).SetYesNoCancelResult(TestKp2aApp.YesNoCancelResult.Yes);
+
//save the database from app 2: This save operation must detect the changes made from app 1 and ask if it should sync:
SaveDatabase(app2);
+ //make sure the right question was asked
+ Assert.AreEqual(UiStringKey.TitleSyncQuestion, ((TestKp2aApp)app2).LastYesNoCancelQuestionTitle);
+
//add group 2 to app 1:
app.GetDb().KpDatabase.RootGroup.AddGroup(group2, true);
@@ -68,7 +76,162 @@ namespace Kp2aUnitTests
//ensure the sync was successful:
AssertDatabasesAreEqual(app.GetDb().KpDatabase, resultApp.GetDb().KpDatabase);
- Assert.IsTrue(false, "todo: test for sync question, test overwrite or cancel!");
+ }
+
+
+ [TestMethod]
+ public void TestLoadEditSaveWithSyncOverwrite()
+ {
+ //create the default database:
+ IKp2aApp app = SetupAppWithDefaultDatabase();
+ //save it and reload it so we have a base version
+ SaveDatabase(app);
+ app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
+ //load it once again:
+ IKp2aApp app2 = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
+
+ //modify the database by adding a group in both databases:
+ app.GetDb().KpDatabase.RootGroup.AddGroup(new PwGroup(true, true, "TestGroup", PwIcon.Apple), true);
+ var group2 = new PwGroup(true, true, "TestGroup2", PwIcon.Energy);
+ app2.GetDb().KpDatabase.RootGroup.AddGroup(group2, true);
+ //save the database from app 1:
+ SaveDatabase(app);
+
+ //the user clicks the "no" button when asked if the sync should be performed -> overwrite expected!
+ ((TestKp2aApp)app2).SetYesNoCancelResult(TestKp2aApp.YesNoCancelResult.No);
+
+ //save the database from app 2: This save operation must detect the changes made from app 1 and ask if it should sync:
+ SaveDatabase(app2);
+
+ //make sure the right question was asked
+ Assert.AreEqual(UiStringKey.TitleSyncQuestion, ((TestKp2aApp)app2).LastYesNoCancelQuestionTitle);
+
+ //load database to a new app instance:
+ IKp2aApp resultApp = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
+
+ //ensure the sync was NOT performed (overwrite expected!):
+ AssertDatabasesAreEqual(app2.GetDb().KpDatabase, resultApp.GetDb().KpDatabase);
+
+ }
+
+
+ [TestMethod]
+ public void TestLoadEditSaveWithSyncOverwriteBecauseOfNoCheck()
+ {
+ //create the default database:
+ IKp2aApp app = SetupAppWithDefaultDatabase();
+ //save it and reload it so we have a base version
+ SaveDatabase(app);
+ app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
+ //load it once again:
+ IKp2aApp app2 = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
+
+ //modify the database by adding a group in both databases:
+ app.GetDb().KpDatabase.RootGroup.AddGroup(new PwGroup(true, true, "TestGroup", PwIcon.Apple), true);
+ var group2 = new PwGroup(true, true, "TestGroup2", PwIcon.Energy);
+ app2.GetDb().KpDatabase.RootGroup.AddGroup(group2, true);
+ //save the database from app 1:
+ SaveDatabase(app);
+
+ //the user doesn't want to perform check for file change:
+ ((TestKp2aApp) app2).SetPreference(PreferenceKey.CheckForFileChangesOnSave, false);
+
+ //save the database from app 2: This save operation must detect the changes made from app 1 and ask if it should sync:
+ SaveDatabase(app2);
+
+ //make sure no question was asked
+ Assert.AreEqual(null, ((TestKp2aApp)app2).LastYesNoCancelQuestionTitle);
+
+ //load database to a new app instance:
+ IKp2aApp resultApp = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
+
+ //ensure the sync was NOT performed (overwrite expected!):
+ AssertDatabasesAreEqual(app2.GetDb().KpDatabase, resultApp.GetDb().KpDatabase);
+
+ }
+
+ [TestMethod]
+ public void TestLoadEditSaveWithSyncCancel()
+ {
+ //create the default database:
+ IKp2aApp app = SetupAppWithDefaultDatabase();
+ //save it and reload it so we have a base version
+ SaveDatabase(app);
+ app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
+ //load it once again:
+ IKp2aApp app2 = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
+
+ //modify the database by adding a group in both databases:
+ app.GetDb().KpDatabase.RootGroup.AddGroup(new PwGroup(true, true, "TestGroup", PwIcon.Apple), true);
+ var group2 = new PwGroup(true, true, "TestGroup2", PwIcon.Energy);
+ app2.GetDb().KpDatabase.RootGroup.AddGroup(group2, true);
+ //save the database from app 1:
+ SaveDatabase(app);
+
+ //the user clicks the "cancel" button when asked if the sync should be performed
+ ((TestKp2aApp)app2).SetYesNoCancelResult(TestKp2aApp.YesNoCancelResult.Cancel);
+
+ //save the database from app 2: This save operation must detect the changes made from app 1 and ask if it should sync:
+ Assert.AreEqual(false, TrySaveDatabase(app2));
+
+ //make sure the right question was asked
+ Assert.AreEqual(UiStringKey.TitleSyncQuestion, ((TestKp2aApp)app2).LastYesNoCancelQuestionTitle);
+
+ //load database to a new app instance:
+ IKp2aApp resultApp = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
+
+ //ensure the sync was NOT performed (cancel expected!):
+ AssertDatabasesAreEqual(app.GetDb().KpDatabase, resultApp.GetDb().KpDatabase);
+
+ }
+
+
+ [TestMethod]
+ public void TestLoadEditSaveWithSyncConflict()
+ {
+
+ //create the default database:
+ IKp2aApp app = SetupAppWithDefaultDatabase();
+ //save it and reload it so we have a base version
+ SaveDatabase(app);
+ app = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
+ //load it once again:
+ IKp2aApp app2 = LoadDatabase(DefaultFilename, DefaultPassword, DefaultKeyfile);
+
+ //modify the database by renaming the same group in both databases:
+ app.GetDb().KpDatabase.RootGroup.Groups.Single(g => g.Name == "Internet").Name += "abc";
+ app2.GetDb().KpDatabase.RootGroup.Groups.Single(g => g.Name == "Internet").Name += "abcde";
+ //app1 also changes the master password:
+ var compositeKey = app.GetDb().KpDatabase.MasterKey;
+ compositeKey.RemoveUserKey(compositeKey.GetUserKey(typeof (KcpPassword)));
+ compositeKey.AddUserKey(new KcpPassword("abc"));
+
+ //save the database from app 1:
+ SaveDatabase(app);
+
+
+ ((TestKp2aApp)app2).SetYesNoCancelResult(TestKp2aApp.YesNoCancelResult.Yes);
+
+ //save the database from app 2: This save operation must fail because the target file cannot be loaded:
+ Assert.IsFalse(TrySaveDatabase(app2));
+
+ //make sure the right question was asked
+ Assert.AreEqual(UiStringKey.TitleSyncQuestion, ((TestKp2aApp)app2).LastYesNoCancelQuestionTitle);
+
+ }
+
+
+
+ [TestMethod]
+ public void TestSaveAsWhenReadOnly()
+ {
+ Assert.Fail("TODO: Test ");
+ }
+
+ [TestMethod]
+ public void TestSaveAsWhenSyncError()
+ {
+ Assert.Fail("TODO: Test ");
}
[TestMethod]
@@ -119,4 +282,6 @@ namespace Kp2aUnitTests
return sOutput.Text;
}
}
+
+
}
diff --git a/src/keepass2android/EntryActivity.cs b/src/keepass2android/EntryActivity.cs
index 5e49f64b..eb52839c 100644
--- a/src/keepass2android/EntryActivity.cs
+++ b/src/keepass2android/EntryActivity.cs
@@ -123,8 +123,8 @@ namespace keepass2android
Entry.Expires = true;
Entry.Touch(true);
RequiresRefresh();
- UpdateEntry update = new UpdateEntry(this, App.Kp2a.GetDb(), backupEntry, Entry, null);
- ProgressTask pt = new ProgressTask(App.Kp2a, this, update, UiStringKey.saving_database);
+ UpdateEntry update = new UpdateEntry(this, App.Kp2a, backupEntry, Entry, null);
+ ProgressTask pt = new ProgressTask(App.Kp2a, this, update);
pt.Run();
}
FillData(false);
diff --git a/src/keepass2android/EntryEditActivity.cs b/src/keepass2android/EntryEditActivity.cs
index 03a3745d..9fd89b12 100644
--- a/src/keepass2android/EntryEditActivity.cs
+++ b/src/keepass2android/EntryEditActivity.cs
@@ -383,11 +383,11 @@ namespace keepass2android
},closeOrShowError);
if ( State.IsNew ) {
- runnable = AddEntry.GetInstance(this, App.Kp2a.GetDb(), newEntry, State.ParentGroup, afterAddEntry);
+ runnable = AddEntry.GetInstance(this, App.Kp2a, newEntry, State.ParentGroup, afterAddEntry);
} else {
- runnable = new UpdateEntry(this, App.Kp2a.GetDb(), initialEntry, newEntry, closeOrShowError);
+ runnable = new UpdateEntry(this, App.Kp2a, initialEntry, newEntry, closeOrShowError);
}
- ProgressTask pt = new ProgressTask(App.Kp2a, act, runnable, UiStringKey.saving_database);
+ ProgressTask pt = new ProgressTask(App.Kp2a, act, runnable);
pt.Run();
diff --git a/src/keepass2android/GroupActivity.cs b/src/keepass2android/GroupActivity.cs
index 4eec2ca2..44cf124e 100644
--- a/src/keepass2android/GroupActivity.cs
+++ b/src/keepass2android/GroupActivity.cs
@@ -177,8 +177,8 @@ namespace keepass2android
int groupIconId = data.Extras.GetInt(GroupEditActivity.KeyIconId);
GroupBaseActivity act = this;
Handler handler = new Handler();
- AddGroup task = AddGroup.GetInstance(this, App.Kp2a.GetDb(), groupName, groupIconId, Group, new RefreshTask(handler, this), false);
- ProgressTask pt = new ProgressTask(App.Kp2a, act, task, UiStringKey.saving_database);
+ AddGroup task = AddGroup.GetInstance(this, App.Kp2a, groupName, groupIconId, Group, new RefreshTask(handler, this), false);
+ ProgressTask pt = new ProgressTask(App.Kp2a, act, task);
pt.Run();
break;
diff --git a/src/keepass2android/PasswordActivity.cs b/src/keepass2android/PasswordActivity.cs
index 31bf4587..21738fbb 100644
--- a/src/keepass2android/PasswordActivity.cs
+++ b/src/keepass2android/PasswordActivity.cs
@@ -365,7 +365,7 @@ namespace keepass2android
Handler handler = new Handler();
LoadDb task = new LoadDb(App.Kp2a, _ioConnection, pass, key, new AfterLoad(handler, this));
- ProgressTask pt = new ProgressTask(App.Kp2a, this, task, UiStringKey.loading_database);
+ ProgressTask pt = new ProgressTask(App.Kp2a, this, task);
pt.Run();
};
diff --git a/src/keepass2android/Resources/Resource.designer.cs b/src/keepass2android/Resources/Resource.designer.cs
index ec16ac2f..bd47f390 100644
--- a/src/keepass2android/Resources/Resource.designer.cs
+++ b/src/keepass2android/Resources/Resource.designer.cs
@@ -1230,6 +1230,12 @@ namespace keepass2android
// aapt resource value: 0x7f080033
public const int AboutText = 2131230771;
+ // aapt resource value: 0x7f08011e
+ public const int AddingEntry = 2131231006;
+
+ // aapt resource value: 0x7f08011f
+ public const int AddingGroup = 2131231007;
+
// aapt resource value: 0x7f080114
public const int AskDeletePermanentlyEntry = 2131230996;
@@ -1278,29 +1284,32 @@ namespace keepass2android
// aapt resource value: 0x7f0800f5
public const int BinaryDirectory_title = 2131230965;
- // aapt resource value: 0x7f080125
- public const int ChangeLog = 2131231013;
+ // aapt resource value: 0x7f08012f
+ public const int ChangeLog = 2131231023;
- // aapt resource value: 0x7f080124
- public const int ChangeLog_0_7 = 2131231012;
+ // aapt resource value: 0x7f08012e
+ public const int ChangeLog_0_7 = 2131231022;
- // aapt resource value: 0x7f080122
- public const int ChangeLog_0_8 = 2131231010;
+ // aapt resource value: 0x7f08012c
+ public const int ChangeLog_0_8 = 2131231020;
- // aapt resource value: 0x7f080121
- public const int ChangeLog_0_8_1 = 2131231009;
+ // aapt resource value: 0x7f08012b
+ public const int ChangeLog_0_8_1 = 2131231019;
- // aapt resource value: 0x7f080120
- public const int ChangeLog_0_8_2 = 2131231008;
+ // aapt resource value: 0x7f08012a
+ public const int ChangeLog_0_8_2 = 2131231018;
- // aapt resource value: 0x7f08011f
- public const int ChangeLog_0_8_3 = 2131231007;
+ // aapt resource value: 0x7f080129
+ public const int ChangeLog_0_8_3 = 2131231017;
- // aapt resource value: 0x7f080123
- public const int ChangeLog_keptDonate = 2131231011;
+ // aapt resource value: 0x7f08012d
+ public const int ChangeLog_keptDonate = 2131231021;
- // aapt resource value: 0x7f08011e
- public const int ChangeLog_title = 2131231006;
+ // aapt resource value: 0x7f080128
+ public const int ChangeLog_title = 2131231016;
+
+ // aapt resource value: 0x7f080127
+ public const int CheckingTargetFileForChanges = 2131231015;
// aapt resource value: 0x7f080048
public const int ClearClipboard = 2131230792;
@@ -1311,6 +1320,15 @@ namespace keepass2android
// aapt resource value: 0x7f080034
public const int CreditsText = 2131230772;
+ // aapt resource value: 0x7f080125
+ public const int DecodingDatabase = 2131231013;
+
+ // aapt resource value: 0x7f080120
+ public const int DeletingEntry = 2131231008;
+
+ // aapt resource value: 0x7f080121
+ public const int DeletingGroup = 2131231009;
+
// aapt resource value: 0x7f080081
public const int FileNotFound = 2131230849;
@@ -1335,6 +1353,9 @@ namespace keepass2android
// aapt resource value: 0x7f08010c
public const int OpenKp2aKeyboardAutomatically_title = 2131230988;
+ // aapt resource value: 0x7f080126
+ public const int ParsingDatabase = 2131231014;
+
// aapt resource value: 0x7f080023
public const int QuickUnlockDefaultEnabled_key = 2131230755;
@@ -1389,6 +1410,9 @@ namespace keepass2android
// aapt resource value: 0x7f0800fb
public const int SaveAttachment_doneMessage = 2131230971;
+ // aapt resource value: 0x7f080122
+ public const int SettingPassword = 2131231010;
+
// aapt resource value: 0x7f080109
public const int ShowCopyToClipboardNotification_summary = 2131230985;
@@ -1422,9 +1446,15 @@ namespace keepass2android
// aapt resource value: 0x7f0800de
public const int TanExpiresOnUse_title = 2131230942;
+ // aapt resource value: 0x7f080124
+ public const int TransformingKey = 2131231012;
+
// aapt resource value: 0x7f08002b
public const int TranslationURL = 2131230763;
+ // aapt resource value: 0x7f080123
+ public const int UndoingChanges = 2131231011;
+
// aapt resource value: 0x7f080026
public const int UsageCount_key = 2131230758;
diff --git a/src/keepass2android/Resources/values/strings.xml b/src/keepass2android/Resources/values/strings.xml
index f1398952..9e907d92 100644
--- a/src/keepass2android/Resources/values/strings.xml
+++ b/src/keepass2android/Resources/values/strings.xml
@@ -240,6 +240,17 @@
Suggest or vote for improvements
Rate this app
Translate KP2A
+ Adding entry…
+ Adding group…
+ Deleting entry…
+ Deleting group…
+ Setting password…
+ Undoing changes…
+ Transforming master key…
+ Decoding database…
+ Parsing database…
+ Checking target file for changes…
+
Change log
Version 0.8.3\n
* Username/TAN index displayed in entry list (see settings)\n
diff --git a/src/keepass2android/SetPasswordDialog.cs b/src/keepass2android/SetPasswordDialog.cs
index 059a0088..86371b28 100644
--- a/src/keepass2android/SetPasswordDialog.cs
+++ b/src/keepass2android/SetPasswordDialog.cs
@@ -71,8 +71,8 @@ namespace keepass2android
}
- SetPassword sp = new SetPassword(Context, App.Kp2a.GetDb(), pass, keyfile, new AfterSave(this, _finish, new Handler()));
- ProgressTask pt = new ProgressTask(App.Kp2a, Context, sp, UiStringKey.saving_database);
+ SetPassword sp = new SetPassword(Context, App.Kp2a, pass, keyfile, new AfterSave(this, _finish, new Handler()));
+ ProgressTask pt = new ProgressTask(App.Kp2a, Context, sp);
pt.Run();
};
diff --git a/src/keepass2android/app/App.cs b/src/keepass2android/app/App.cs
index a450637e..29e7c909 100644
--- a/src/keepass2android/app/App.cs
+++ b/src/keepass2android/app/App.cs
@@ -22,6 +22,7 @@ using Android.OS;
using Android.Runtime;
using KeePassLib.Serialization;
using Android.Preferences;
+using keepass2android.Io;
namespace keepass2android
{
@@ -223,6 +224,11 @@ namespace keepass2android
return new RealProgressDialog(ctx);
}
+ public IFileStorage GetFileStorage(IOConnectionInfo iocInfo)
+ {
+ return new BuiltInFileStorage();
+ }
+
internal void OnTerminate()
{
diff --git a/src/keepass2android/fileselect/FileSelectActivity.cs b/src/keepass2android/fileselect/FileSelectActivity.cs
index 5533e0b9..882b7fcf 100644
--- a/src/keepass2android/fileselect/FileSelectActivity.cs
+++ b/src/keepass2android/fileselect/FileSelectActivity.cs
@@ -170,8 +170,7 @@ namespace keepass2android
CreateDb create = new CreateDb(App.Kp2a, this, IOConnectionInfo.FromPath(filename), collectPassword, true);
ProgressTask createTask = new ProgressTask(
App.Kp2a,
- this, create,
- UiStringKey.progress_create);
+ this, create);
createTask.Run();
@@ -313,7 +312,8 @@ namespace keepass2android
GroupActivity.Launch(_activity, _activity.AppTask);
} else {
- IOConnection.DeleteFile(_ioc);
+ App.Kp2a.GetFileStorage(_ioc).DeleteFile(_ioc);
+
}
}
}
diff --git a/src/keepass2android/settings/AppSettingsActivity.cs b/src/keepass2android/settings/AppSettingsActivity.cs
index 2f617f99..6f2741b7 100644
--- a/src/keepass2android/settings/AppSettingsActivity.cs
+++ b/src/keepass2android/settings/AppSettingsActivity.cs
@@ -73,7 +73,7 @@ namespace keepass2android
String previousUsername = db.KpDatabase.DefaultUserName;
db.KpDatabase.DefaultUserName = e.NewValue.ToString();
- SaveDb save = new SaveDb(this, App.Kp2a.GetDb(), new ActionOnFinish( (success, message) =>
+ SaveDb save = new SaveDb(this, App.Kp2a, new ActionOnFinish( (success, message) =>
{
if (!success)
{
@@ -82,7 +82,7 @@ namespace keepass2android
Toast.MakeText(this, message, ToastLength.Long).Show();
}
}));
- ProgressTask pt = new ProgressTask(App.Kp2a, this, save, UiStringKey.saving_database);
+ ProgressTask pt = new ProgressTask(App.Kp2a, this, save);
pt.Run();
};
@@ -95,7 +95,7 @@ namespace keepass2android
String previousName = db.KpDatabase.Name;
db.KpDatabase.Name = e.NewValue.ToString();
- SaveDb save = new SaveDb(this, App.Kp2a.GetDb(), new ActionOnFinish( (success, message) =>
+ SaveDb save = new SaveDb(this, App.Kp2a, new ActionOnFinish( (success, message) =>
{
if (!success)
{
@@ -104,7 +104,7 @@ namespace keepass2android
Toast.MakeText(this, message, ToastLength.Long).Show();
}
}));
- ProgressTask pt = new ProgressTask(App.Kp2a, this, save, UiStringKey.saving_database);
+ ProgressTask pt = new ProgressTask(App.Kp2a, this, save);
pt.Run();
};
diff --git a/src/keepass2android/settings/RoundsPreference.cs b/src/keepass2android/settings/RoundsPreference.cs
index 2f0abf58..9bd50e56 100644
--- a/src/keepass2android/settings/RoundsPreference.cs
+++ b/src/keepass2android/settings/RoundsPreference.cs
@@ -80,8 +80,8 @@ namespace keepass2android.settings
PwDatabase.KeyEncryptionRounds = rounds;
Handler handler = new Handler();
- SaveDb save = new SaveDb(Context, App.Kp2a.GetDb(), new AfterSave(Context, handler, oldRounds, this));
- ProgressTask pt = new ProgressTask(App.Kp2a, Context, save, UiStringKey.saving_database);
+ SaveDb save = new SaveDb(Context, App.Kp2a, new AfterSave(Context, handler, oldRounds, this));
+ ProgressTask pt = new ProgressTask(App.Kp2a, Context, save);
pt.Run();
}