From d93946ed0574c1fcb9def8426e6ba8f84b5ffdce Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Sun, 13 Jul 2014 20:58:10 +0200 Subject: [PATCH] + first version of MasterKee plugin --- .gitignore | 22 + src/KeePass.sln | 66 ++ src/MPTest/MpTest.cs | 23 +- src/MasterKeePlugin/AccessReceiver.cs | 38 ++ src/MasterKeePlugin/ActionReceiver.cs | 80 +++ src/MasterKeePlugin/AddMasterKeeActivity.cs | 26 + src/MasterKeePlugin/Assets/AboutAssets.txt | 19 + src/MasterKeePlugin/LoadingDialog.cs | 156 +++++ src/MasterKeePlugin/MainActivity.cs | 110 ++++ src/MasterKeePlugin/MasterKeePlugin.csproj | 124 ++++ src/MasterKeePlugin/MemUtil.cs | 567 +++++++++++++++++ .../Properties/AndroidManifest.xml | 5 + .../Properties/AssemblyInfo.cs | 30 + .../Resources/AboutResources.txt | 50 ++ .../Resources/drawable-hdpi/ic_launcher.png | Bin 0 -> 4040 bytes .../Resources/drawable-mdpi/ic_launcher.png | Bin 0 -> 2431 bytes .../Resources/drawable-xhdpi/ic_launcher.png | Bin 0 -> 5479 bytes .../Resources/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 8189 bytes .../drawable-xxxhdpi/ic_launcher.png | Bin 0 -> 11511 bytes .../Resources/drawable/Icon.png | Bin 0 -> 4147 bytes .../Resources/drawable/ic_launcher.png | Bin 0 -> 4040 bytes .../Resources/drawable/ic_menu_view.png | Bin 0 -> 1508 bytes .../Resources/layout/AddMkEntry.axml | 7 + .../Resources/layout/Main.axml | 31 + .../Resources/layout/Setup.axml | 56 ++ .../Resources/values/Strings.xml | 17 + .../SetupMasterEntryActivity.cs | 121 ++++ src/MasterPassword/MpAlgorithm.cs | 66 +- src/PluginHostTest/PluginHostTest.csproj | 3 + .../Resources/Values/strings.xml | 590 ++++++++---------- .../GoogleDriveFileStorage.java | 7 +- .../bin/keepass2androidpluginsdk.jar | Bin 20175 -> 20359 bytes .../pluginsdk/AccessManager.java | 4 +- .../PluginAccessBroadcastReceiver.java | 8 +- .../EntryActivityClasses/ExtraStringView.cs | 2 + src/keepass2android/keepass2android.csproj | 4 +- 36 files changed, 1865 insertions(+), 367 deletions(-) create mode 100644 src/MasterKeePlugin/AccessReceiver.cs create mode 100644 src/MasterKeePlugin/ActionReceiver.cs create mode 100644 src/MasterKeePlugin/AddMasterKeeActivity.cs create mode 100644 src/MasterKeePlugin/Assets/AboutAssets.txt create mode 100644 src/MasterKeePlugin/LoadingDialog.cs create mode 100644 src/MasterKeePlugin/MainActivity.cs create mode 100644 src/MasterKeePlugin/MasterKeePlugin.csproj create mode 100644 src/MasterKeePlugin/MemUtil.cs create mode 100644 src/MasterKeePlugin/Properties/AndroidManifest.xml create mode 100644 src/MasterKeePlugin/Properties/AssemblyInfo.cs create mode 100644 src/MasterKeePlugin/Resources/AboutResources.txt create mode 100644 src/MasterKeePlugin/Resources/drawable-hdpi/ic_launcher.png create mode 100644 src/MasterKeePlugin/Resources/drawable-mdpi/ic_launcher.png create mode 100644 src/MasterKeePlugin/Resources/drawable-xhdpi/ic_launcher.png create mode 100644 src/MasterKeePlugin/Resources/drawable-xxhdpi/ic_launcher.png create mode 100644 src/MasterKeePlugin/Resources/drawable-xxxhdpi/ic_launcher.png create mode 100644 src/MasterKeePlugin/Resources/drawable/Icon.png create mode 100644 src/MasterKeePlugin/Resources/drawable/ic_launcher.png create mode 100644 src/MasterKeePlugin/Resources/drawable/ic_menu_view.png create mode 100644 src/MasterKeePlugin/Resources/layout/AddMkEntry.axml create mode 100644 src/MasterKeePlugin/Resources/layout/Main.axml create mode 100644 src/MasterKeePlugin/Resources/layout/Setup.axml create mode 100644 src/MasterKeePlugin/Resources/values/Strings.xml create mode 100644 src/MasterKeePlugin/SetupMasterEntryActivity.cs diff --git a/.gitignore b/.gitignore index 7d8941dd..ec4e4d19 100644 --- a/.gitignore +++ b/.gitignore @@ -260,3 +260,25 @@ Thumbs.db /src/java/PluginInputStick/icons /src/PluginSdkBinding/bin/Release + +/src/MasterPassword/bin/Debug + +/src/MasterPassword/obj/Debug + +/src/MasterPassword/obj/Release + +/src/MPTest/bin/Debug +/src/MPTest/obj/Debug + +/src/MasterKeePlugin/obj/Release +/src/MasterKeePlugin/bin/Debug + +/src/MasterKeePlugin/bin/Release + +/src/MasterKeePlugin/obj/Debug +/src/PluginSdkBinding/obj/Release + +/src/MasterPassword/bin/Release +/src/java/MasterKee + +/src/PluginSdkBinding/obj/ReleaseNoNet diff --git a/src/KeePass.sln b/src/KeePass.sln index abdf5c86..edd7437b 100644 --- a/src/KeePass.sln +++ b/src/KeePass.sln @@ -29,6 +29,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginTOTP", "PluginTOTP\Pl EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginHostTest", "PluginHostTest\PluginHostTest.csproj", "{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterKeePlugin", "MasterKeePlugin\MasterKeePlugin.csproj", "{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterPassword", "MasterPassword\MasterPassword.csproj", "{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MPTest", "MPTest\MPTest.csproj", "{96A3EA5A-7024-479F-A5B1-06654D0867A3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -336,6 +342,66 @@ Global {C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.ReleaseNoNet|Mixed Platforms.Deploy.0 = Release|Any CPU {C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU {C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|Mixed Platforms.Deploy.0 = Debug|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|Win32.ActiveCfg = Debug|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|x64.ActiveCfg = Debug|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|Any CPU.Build.0 = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|Any CPU.Deploy.0 = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|Mixed Platforms.Deploy.0 = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|Win32.ActiveCfg = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|x64.ActiveCfg = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|Any CPU.Deploy.0 = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|Mixed Platforms.Deploy.0 = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU + {9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Debug|Win32.ActiveCfg = Debug|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Debug|x64.ActiveCfg = Debug|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Release|Any CPU.Build.0 = Release|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Release|Win32.ActiveCfg = Release|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Release|x64.ActiveCfg = Release|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU + {2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.Debug|Win32.ActiveCfg = Debug|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.Debug|x64.ActiveCfg = Debug|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.Release|Any CPU.Build.0 = Release|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.Release|Win32.ActiveCfg = Release|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.Release|x64.ActiveCfg = Release|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU + {96A3EA5A-7024-479F-A5B1-06654D0867A3}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/MPTest/MpTest.cs b/src/MPTest/MpTest.cs index 3dfb0d15..e58b6d63 100644 --- a/src/MPTest/MpTest.cs +++ b/src/MPTest/MpTest.cs @@ -11,6 +11,21 @@ namespace MPTest [TestClass()] public class MpAlgorithmTests { + + static sbyte[] ToSignedByteArray(byte[] unsigned) + { + sbyte[] signed = new sbyte[unsigned.Length]; + Buffer.BlockCopy(unsigned, 0, signed, 0, unsigned.Length); + return signed; + } + static byte[] ToUnsignedByteArray(sbyte[] signed) + { + byte[] unsigned = new byte[signed.Length]; + Buffer.BlockCopy(signed, 0, unsigned, 0, signed.Length); + return unsigned; + } + + private static byte[] HashHMAC(byte[] key, byte[] message) { var hash = new HMACSHA256(key); @@ -27,9 +42,9 @@ namespace MPTest -126, 24, 15, 65, 9, 17, 0, 123, 91, 105, -46, -99, -64, 123, -12, 80, -37, -77 }; var result = MpAlgorithm.GetKeyForPassword("u", "test"); - - Assert.IsTrue(expectedRes.SequenceEqual(result)); - + + Assert.IsTrue(expectedRes.SequenceEqual(ToSignedByteArray(result))); + } [TestMethod] public void GenerateContentTest() @@ -63,7 +78,7 @@ namespace MPTest { -53, -69, -89, 48, 122, 56, 34, 13, -70, -103, 102, 90, -96, -75, 45, 68, 43, 67, 97, 60, 84, -90, 98, -95, -2, -2, 99, -60, -121, -2, -26, -45, 53, -31, 47, 0, -46, -97, 77, -41, 63, -15, -30, 60, 4, -120, 32, 122, -94, 42, 122, -103, -61, -115, 75, -123, -15, 47, 61, -100, -119, 115, 118, 82 }; - Assert.IsTrue(expected.SequenceEqual(key)); + Assert.IsTrue(expected.SequenceEqual(ToSignedByteArray(key))); } } } diff --git a/src/MasterKeePlugin/AccessReceiver.cs b/src/MasterKeePlugin/AccessReceiver.cs new file mode 100644 index 00000000..752b168f --- /dev/null +++ b/src/MasterKeePlugin/AccessReceiver.cs @@ -0,0 +1,38 @@ +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 Keepass2android.Pluginsdk; + +namespace MasterKeePlugin +{ + [BroadcastReceiver(Exported = true)] + [IntentFilter(new[] { Strings.ActionTriggerRequestAccess, Strings.ActionReceiveAccess, Strings.ActionRevokeAccess })] + public class AccessReceiver: PluginAccessBroadcastReceiver + { + public override void OnReceive(Context context, Intent intent) + { + Android.Util.Log.Debug("KP2A_MasterKee", intent.Action); + base.OnReceive(context, intent); + } + + public override IList Scopes + { + get + { + return new List + { + Strings.ScopeCurrentEntry, + Strings.ScopeQueryCredentialsForOwnPackage + }; + } + } + } +} \ No newline at end of file diff --git a/src/MasterKeePlugin/ActionReceiver.cs b/src/MasterKeePlugin/ActionReceiver.cs new file mode 100644 index 00000000..c4ec7ba1 --- /dev/null +++ b/src/MasterKeePlugin/ActionReceiver.cs @@ -0,0 +1,80 @@ +using System; +using System.Linq; +using System.Security.Cryptography; +using System.Text; + +using Android.App; +using Android.Content; +using Android.OS; +using Android.Runtime; +using Android.Views; +using Android.Widget; +using Java.Util; +using KeePassLib.Utility; +using Keepass2android.Pluginsdk; + + +namespace MasterKeePlugin +{ + [BroadcastReceiver(Exported = true)] + [IntentFilter(new[] {Strings.ActionOpenEntry, Strings.ActionEntryActionSelected })] + public class ActionReceiver: PluginActionBroadcastReceiver + { + public override void OnReceive(Context context, Intent intent) + { + Android.Util.Log.Debug("KP2A_MasterKee", intent.Action); + base.OnReceive(context, intent); + } + + private static byte[] HashHMAC(byte[] key, byte[] message) + { + var hash = new HMACSHA256(key); + return hash.ComputeHash(message); + } + protected override void OpenEntry(OpenEntryAction oe) + { + string masterkey; + Android.Util.Log.Debug("KP2A_MasterKee", "Opening entry..."); + if (oe.EntryFields.TryGetValue("MK_MasterKey", out masterkey)) + { + Android.Util.Log.Debug("KP2A_MasterKee", "Entry is MK entry."); + string type; + if (!oe.EntryFields.TryGetValue("MK_Type", out type)) + type = "Long Password"; + int counter = 1; + string strCounter; + if (oe.EntryFields.TryGetValue("MK_Site_Counter", out strCounter)) + { + int.TryParse(strCounter, out counter); + } + Android.Util.Log.Debug("KP2A_MasterKee", "Calculating password..."); + string calculatedKey = MasterPassword.MpAlgorithm.GenerateContent(type, + oe.EntryFields[KeepassDefs.TitleField], + MemUtil.HexStringToByteArray(masterkey), + counter, + HashHMAC + ); + Android.Util.Log.Debug("KP2A_MasterKee", "ok. Returning data."); + try + { + oe.SetEntryField(KeepassDefs.PasswordField, calculatedKey, true); + oe.SetEntryField("MK_MasterKey", "", true); + oe.SetEntryField("MK_Type", "", true); + oe.SetEntryField("MK_Site_Counter", "", true); + + } + catch (Exception e) + { + Android.Util.Log.Debug("KP2A_MasterKee", e.ToString()); + } + + } + Android.Util.Log.Debug("KP2A_MasterKee", "Done."); + } + + protected override void ActionSelected(ActionSelectedAction asa) + { + + } + } +} \ No newline at end of file diff --git a/src/MasterKeePlugin/AddMasterKeeActivity.cs b/src/MasterKeePlugin/AddMasterKeeActivity.cs new file mode 100644 index 00000000..ebb998f9 --- /dev/null +++ b/src/MasterKeePlugin/AddMasterKeeActivity.cs @@ -0,0 +1,26 @@ +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; + +namespace MasterKeePlugin +{ + //TODO remove? + [Activity(Label = "@string/AddMkEntry")] + public class AddMasterKeeActivity : Activity + { + protected override void OnCreate(Bundle bundle) + { + base.OnCreate(bundle); + + + } + } +} \ No newline at end of file diff --git a/src/MasterKeePlugin/Assets/AboutAssets.txt b/src/MasterKeePlugin/Assets/AboutAssets.txt new file mode 100644 index 00000000..ee398862 --- /dev/null +++ b/src/MasterKeePlugin/Assets/AboutAssets.txt @@ -0,0 +1,19 @@ +Any raw assets you want to be deployed with your application can be placed in +this directory (and child directories) and given a Build Action of "AndroidAsset". + +These files will be deployed with you package and will be accessible using Android's +AssetManager, like this: + +public class ReadAsset : Activity +{ + protected override void OnCreate (Bundle bundle) + { + base.OnCreate (bundle); + + InputStream input = Assets.Open ("my_asset.txt"); + } +} + +Additionally, some Android functions will automatically load asset files: + +Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf"); \ No newline at end of file diff --git a/src/MasterKeePlugin/LoadingDialog.cs b/src/MasterKeePlugin/LoadingDialog.cs new file mode 100644 index 00000000..e987a49b --- /dev/null +++ b/src/MasterKeePlugin/LoadingDialog.cs @@ -0,0 +1,156 @@ +using System; +using Android.App; +using Android.Content; +using Android.OS; +using Android.Runtime; +using Java.Lang; +using MasterKeePlugin; +using Exception = System.Exception; +using Object = Java.Lang.Object; + +namespace keepass2android.Utils +{ + public class LoadingDialog : AsyncTask + { + private readonly Context _context; + private readonly string _message; + private readonly bool _cancelable; + readonly Func _doInBackground; + readonly Action _onPostExecute; + + private ProgressDialog mDialog; + /** + * Default is {@code 500}ms + */ + private int mDelayTime = 500; + /** + * Flag to use along with {@link #mDelayTime} + */ + private bool mFinished = false; + + private Exception mLastException; + + + public LoadingDialog(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) + { + } + + public LoadingDialog(Context context, string message, bool cancelable, Func doInBackground, + Action onPostExecute) + { + _context = context; + _message = message; + _cancelable = cancelable; + _doInBackground = doInBackground; + _onPostExecute = onPostExecute; + Initialize(); + } + + private void Initialize() + { + mDialog = new ProgressDialog(_context); + mDialog.SetMessage(_message); + mDialog.Indeterminate = true; + mDialog.SetCancelable(_cancelable); + if (_cancelable) + { + mDialog.SetCanceledOnTouchOutside(true); + mDialog.CancelEvent += (sender, args) => mDialog.Cancel(); + } + } + + + protected override void OnPreExecute() + { + new Handler().PostDelayed(() => + { + if (!mFinished) + { + try + { + /* + * sometime the activity has been finished before we + * show this dialog, it will raise error + */ + mDialog.Show(); + } + catch (Exception t) + { + Android.Util.Log.Debug("LD", t.ToString()); + } + } + + } + , mDelayTime); + } + + + /** + * If you override this method, you must call {@code super.onCancelled()} at + * beginning of the method. + */ + protected override void OnCancelled() { + DoFinish(); + base.OnCancelled(); + }// onCancelled() + + private void DoFinish() { + mFinished = true; + try { + /* + * Sometime the activity has been finished before we dismiss this + * dialog, it will raise error. + */ + mDialog.Dismiss(); + } catch (Exception e) + { + Android.Util.Log.Debug("LD", e.ToString()); + } + }// doFinish() + + + /** + * Sets last exception. This method is useful in case an exception raises + * inside {@link #doInBackground(Void...)} + * + * @param t + * {@link Throwable} + */ + protected void SetLastException(Exception e) { + mLastException = e; + }// setLastException() + + /** + * Gets last exception. + * + * @return {@link Throwable} + */ + protected Exception GetLastException() { + return mLastException; + }// getLastException() + + + protected override Object DoInBackground(params Object[] @params) + { + return _doInBackground(@params); + } + + protected override TResult RunInBackground(params TParams[] @params) + { + throw new NotImplementedException(); + } + + protected override void OnPostExecute(Object result) + { + DoFinish(); + + if (_onPostExecute != null) + _onPostExecute(result); + } + + + + + + } +} \ No newline at end of file diff --git a/src/MasterKeePlugin/MainActivity.cs b/src/MasterKeePlugin/MainActivity.cs new file mode 100644 index 00000000..0f06e7ff --- /dev/null +++ b/src/MasterKeePlugin/MainActivity.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using Android.App; +using Android.Content; +using Android.Preferences; +using Android.Runtime; +using Android.Views; +using Android.Widget; +using Android.OS; +using Keepass2android.Pluginsdk; + +namespace MasterKeePlugin +{ + [Activity(Label = "MasterKee", MainLauncher = true, Icon = "@drawable/ic_launcher")] + public class MainActivity : Activity + { + private const string KEY_MK_ENTRY_ID = "KEY_MK_ENTRY_ID"; + + + protected override void OnCreate(Bundle bundle) + { + base.OnCreate(bundle); + + // Set our view from the "main" layout resource + SetContentView(Resource.Layout.Main); + + + Button buttonSelect = FindViewById