Implemented UI for sync

Fixed bugs
This commit is contained in:
Philipp Crocoll 2013-07-11 17:27:10 +02:00
parent 16c08cbe8a
commit deeaa673a5
14 changed files with 630 additions and 548 deletions

View File

@ -27,10 +27,16 @@ namespace keepass2android.Io
{ {
if (!ioc.IsLocalFile()) if (!ioc.IsLocalFile())
return false; return false;
DateTime previousDate; if (previousFileVersion == null)
if (!DateTime.TryParse(previousFileVersion, out previousDate))
return false; return false;
return File.GetLastWriteTimeUtc(ioc.Path) > previousDate; DateTime previousDate;
if (!DateTime.TryParse(previousFileVersion, CultureInfo.InvariantCulture, DateTimeStyles.None, out previousDate))
return false;
DateTime currentModificationDate = File.GetLastWriteTimeUtc(ioc.Path);
TimeSpan diff = currentModificationDate - previousDate;
return diff > TimeSpan.FromSeconds(1);
//don't use > operator because milliseconds are truncated
return File.GetLastWriteTimeUtc(ioc.Path) - previousDate >= TimeSpan.FromSeconds(1);
} }

View File

@ -43,6 +43,7 @@ namespace keepass2android.Io
/// </summary> /// </summary>
/// Note: This function may return false even if the file might have changed. The function /// 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. /// should focus on being fast and cheap instead of doing things like hashing or downloading a full file.
/// previousFileVersion may be null to indicate no previous version is known.
/// <returns>Returns true if a change was detected, false otherwise.</returns> /// <returns>Returns true if a change was detected, false otherwise.</returns>
bool CheckForFileChangeFast(IOConnectionInfo ioc , string previousFileVersion); bool CheckForFileChangeFast(IOConnectionInfo ioc , string previousFileVersion);

View File

@ -60,7 +60,7 @@ namespace keepass2android
{ {
_handler.Post(() => _handler.Post(() =>
{ {
if (String.IsNullOrEmpty(submessage)) if (!String.IsNullOrEmpty(submessage))
{ {
_progressDialog.SetMessage(_message + " (" + submessage + ")"); _progressDialog.SetMessage(_message + " (" + submessage + ")");
} }

View File

@ -29,7 +29,7 @@ namespace keepass2android
ParsingDatabase, ParsingDatabase,
CheckingTargetFileForChanges, CheckingTargetFileForChanges,
TitleSyncQuestion, TitleSyncQuestion,
MessageSyncQuestions, MessageSyncQuestion,
SynchronizingDatabase SynchronizingDatabase
} }
} }

View File

@ -75,8 +75,9 @@ namespace keepass2android
if (fileStorage.CheckForFileChangeFast(ioc, _app.GetDb().LastFileVersion) //first try to use the fast change detection 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: || (FileHashChanged(ioc, _app.GetDb().KpDatabase.HashOfFileOnDisk))) //if that fails, hash the file and compare:
{ {
//ask user... //ask user...
_app.AskYesNoCancel(UiStringKey.TitleSyncQuestion, UiStringKey.MessageSyncQuestions, _app.AskYesNoCancel(UiStringKey.TitleSyncQuestion, UiStringKey.MessageSyncQuestion,
//yes = sync //yes = sync
(sender, args) => (sender, args) =>
{ {
@ -85,7 +86,6 @@ namespace keepass2android
//note: when synced, the file might be downloaded once again from the server. Caching the data //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 //in the hashing function would solve this but increases complexity. I currently assume the files are
//small. //small.
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.SynchronizingDatabase));
MergeIn(fileStorage, ioc); MergeIn(fileStorage, ioc);
PerformSaveWithoutCheck(fileStorage, ioc); PerformSaveWithoutCheck(fileStorage, ioc);
Finish(true); Finish(true);
@ -108,8 +108,6 @@ namespace keepass2android
}, },
_ctx _ctx
); );
} }
else else
{ {
@ -125,7 +123,8 @@ namespace keepass2android
bSuccess = false; bSuccess = false;
} }
*/ */
Finish (false, e.ToString()); Kp2aLog.Log("Error while saving: "+e.ToString());
Finish (false, e.Message);
return; return;
} }
} }
@ -138,7 +137,7 @@ namespace keepass2android
try try
{ {
_workerThread = new Thread(runHandler); _workerThread = new Thread(runHandler);
_workerThread.Run(); _workerThread.Start();
} }
catch (Exception e) catch (Exception e)
{ {
@ -156,6 +155,8 @@ namespace keepass2android
private void MergeIn(IFileStorage fileStorage, IOConnectionInfo ioc) private void MergeIn(IFileStorage fileStorage, IOConnectionInfo ioc)
{ {
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.SynchronizingDatabase));
PwDatabase pwImp = new PwDatabase(); PwDatabase pwImp = new PwDatabase();
PwDatabase pwDatabase = _app.GetDb().KpDatabase; PwDatabase pwDatabase = _app.GetDb().KpDatabase;
pwImp.New(new IOConnectionInfo(), pwDatabase.MasterKey); pwImp.New(new IOConnectionInfo(), pwDatabase.MasterKey);
@ -170,6 +171,7 @@ namespace keepass2android
private void PerformSaveWithoutCheck(IFileStorage fileStorage, IOConnectionInfo ioc) private void PerformSaveWithoutCheck(IFileStorage fileStorage, IOConnectionInfo ioc)
{ {
StatusLogger.UpdateSubMessage("");
_app.GetDb().SaveData(_ctx); _app.GetDb().SaveData(_ctx);
_app.GetDb().LastFileVersion = fileStorage.GetCurrentFileVersionFast(ioc); _app.GetDb().LastFileVersion = fileStorage.GetCurrentFileVersionFast(ioc);
} }

View File

@ -228,6 +228,14 @@ namespace Kp2aUnitTests
Assert.Fail("TODO: Test "); Assert.Fail("TODO: Test ");
} }
[TestMethod]
public void TestReloadWhenCancelSync()
{
//when a change is detected and the user cancels saving, the app should display the "file was modified - reload?" question.
Assert.Fail("TODO: Test ");
}
[TestMethod] [TestMethod]
public void TestSaveAsWhenSyncError() public void TestSaveAsWhenSyncError()
{ {

View File

@ -42,6 +42,10 @@ namespace keepass2android
if (TimeoutHelper.CheckShutdown(this, _ioc)) if (TimeoutHelper.CheckShutdown(this, _ioc))
return; return;
//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
//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.)
App.Kp2a.CheckForOpenFileChanged(this); App.Kp2a.CheckForOpenFileChanged(this);
} }

View File

@ -53,6 +53,7 @@ namespace keepass2android
if (TimeoutHelper.CheckShutdown(this, _ioc)) if (TimeoutHelper.CheckShutdown(this, _ioc))
return; return;
//todo: see LockCloseActivity.OnResume
App.Kp2a.CheckForOpenFileChanged(this); App.Kp2a.CheckForOpenFileChanged(this);
} }

File diff suppressed because it is too large Load Diff

View File

@ -61,6 +61,8 @@
<string name="LastInfoVersionCode_key">LastInfoVersion</string> <string name="LastInfoVersionCode_key">LastInfoVersion</string>
<string name="UseFileTransactions_key">UseFileTransactions</string> <string name="UseFileTransactions_key">UseFileTransactions</string>
<string name="CheckForFileChangesOnSave_key">CheckForFileChangesOnSave</string>
<string name="MarketURL">market://details?id=</string> <string name="MarketURL">market://details?id=</string>
<string name="SuggestionsURL">https://keepass2android.codeplex.com/workitem/list/basic</string> <string name="SuggestionsURL">https://keepass2android.codeplex.com/workitem/list/basic</string>
<string name="TranslationURL">http://crowdin.net/project/keepass2android</string> <string name="TranslationURL">http://crowdin.net/project/keepass2android</string>

View File

@ -218,6 +218,9 @@
<string name="credentials_dialog_title">Enter server credentials</string> <string name="credentials_dialog_title">Enter server credentials</string>
<string name="UseFileTransactions_title">File transactions</string> <string name="UseFileTransactions_title">File transactions</string>
<string name="UseFileTransactions_summary">Use file transactions for writing databases</string> <string name="UseFileTransactions_summary">Use file transactions for writing databases</string>
<string name="CheckForFileChangesOnSave_title">Check for modifications</string>
<string name="CheckForFileChangesOnSave_summary">Check whether the file was modified externally before saving changes.</string>
<string name="ShowCopyToClipboardNotification_title">Clipboard notifications</string> <string name="ShowCopyToClipboardNotification_title">Clipboard notifications</string>
<string name="ShowCopyToClipboardNotification_summary">Make username and password accessible through the notification bar and clipboard. Beware of password sniffers!</string> <string name="ShowCopyToClipboardNotification_summary">Make username and password accessible through the notification bar and clipboard. Beware of password sniffers!</string>
<string name="ShowKp2aKeyboardNotification_title">KP2A keyboard notification</string> <string name="ShowKp2aKeyboardNotification_title">KP2A keyboard notification</string>
@ -251,8 +254,22 @@
<string name="DecodingDatabase">Decoding database…</string> <string name="DecodingDatabase">Decoding database…</string>
<string name="ParsingDatabase">Parsing database…</string> <string name="ParsingDatabase">Parsing database…</string>
<string name="CheckingTargetFileForChanges">Checking target file for changes…</string> <string name="CheckingTargetFileForChanges">Checking target file for changes…</string>
<string name="TitleSyncQuestion">Merge changes?</string>
<string name="MessageSyncQuestion">The database file was modified externally. Do you want to load and merge the changes before saving? Select No if you want to overwrite the external changes.</string>
<string name="SynchronizingDatabase">Merging changes…</string>
<string name="ChangeLog_title">Change log</string> <string name="ChangeLog_title">Change log</string>
<string name="ChangeLog_0_8_4">
<b>Version 0.8.4</b>\n
* External changes are detected and merged when saving\n
* Improved loading performance\n
* Improved search toolbar with suggestions\n
? New app logo!\n
? Added support for .kdbp format for faster loading/saving\n
? Improved editing of extra strings and hidden display when protected\n
Thanks to Alex Vallat for his code contributions!\n
Thanks to Niki Hüttner (www.close-cut.de) for the new logo!\n
</string>
<string name="ChangeLog_0_8_3"><b>Version 0.8.3</b>\n <string name="ChangeLog_0_8_3"><b>Version 0.8.3</b>\n
* Username/TAN index displayed in entry list (see settings)\n * Username/TAN index displayed in entry list (see settings)\n
* Entries can be created if search from browser doesn\'t return results\n * Entries can be created if search from browser doesn\'t return results\n

View File

@ -149,6 +149,13 @@
android:defaultValue="true" android:defaultValue="true"
android:title="@string/UseFileTransactions_title" android:title="@string/UseFileTransactions_title"
android:key="@string/UseFileTransactions_key" /> android:key="@string/UseFileTransactions_key" />
<CheckBoxPreference
android:enabled="true"
android:persistent="true"
android:summary="@string/CheckForFileChangesOnSave_summary"
android:defaultValue="true"
android:title="@string/CheckForFileChangesOnSave_title"
android:key="@string/CheckForFileChangesOnSave_key" />
</PreferenceScreen> </PreferenceScreen>
</PreferenceScreen> </PreferenceScreen>

View File

@ -103,6 +103,8 @@ namespace keepass2android
return prefs.GetBoolean(ctx.Resources.GetString(Resource.String.keyfile_key), ctx.Resources.GetBoolean(Resource.Boolean.keyfile_default)); return prefs.GetBoolean(ctx.Resources.GetString(Resource.String.keyfile_key), ctx.Resources.GetBoolean(Resource.Boolean.keyfile_default));
case PreferenceKey.UseFileTransactions: case PreferenceKey.UseFileTransactions:
return prefs.GetBoolean(ctx.Resources.GetString(Resource.String.UseFileTransactions_key), true); return prefs.GetBoolean(ctx.Resources.GetString(Resource.String.UseFileTransactions_key), true);
case PreferenceKey.CheckForFileChangesOnSave:
return prefs.GetBoolean(ctx.Resources.GetString(Resource.String.CheckForFileChangesOnSave_key), true);
default: default:
throw new Exception("unexpected key!"); throw new Exception("unexpected key!");
} }
@ -163,7 +165,9 @@ namespace keepass2android
EventHandler<DialogClickEventArgs> cancelHandler, EventHandler<DialogClickEventArgs> cancelHandler,
Context ctx) Context ctx)
{ {
Handler handler = new Handler(Looper.MainLooper);
handler.Post(() =>
{
AlertDialog.Builder builder = new AlertDialog.Builder(ctx); AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.SetTitle(GetResourceString(titleKey)); builder.SetTitle(GetResourceString(titleKey));
@ -178,7 +182,8 @@ namespace keepass2android
Dialog dialog = builder.Create(); Dialog dialog = builder.Create();
dialog.Show(); dialog.Show();
}
);
} }
public Handler UiThreadHandler public Handler UiThreadHandler

View File

@ -371,7 +371,9 @@
</AndroidResource> </AndroidResource>
<AndroidResource Include="Resources\xml\preferences.xml" /> <AndroidResource Include="Resources\xml\preferences.xml" />
<AndroidResource Include="Resources\xml\searchable.xml" /> <AndroidResource Include="Resources\xml\searchable.xml" />
<AndroidResource Include="Resources\values\strings.xml" /> <AndroidResource Include="Resources\values\strings.xml">
<SubType>Designer</SubType>
</AndroidResource>
<AndroidResource Include="Resources\menu-v11\entry.xml" /> <AndroidResource Include="Resources\menu-v11\entry.xml" />
<AndroidResource Include="Resources\menu-v11\password.xml" /> <AndroidResource Include="Resources\menu-v11\password.xml" />
<AndroidResource Include="Resources\menu-v11\entry_edit.xml" /> <AndroidResource Include="Resources\menu-v11\entry_edit.xml" />