diff --git a/.gitignore b/.gitignore index 8d3e8133..76d73205 100644 --- a/.gitignore +++ b/.gitignore @@ -125,3 +125,16 @@ Thumbs.db /src/Kp2aUnitTests/bin/ReleaseNoNet /src/TwofishCipher/bin /src/TwofishCipher/obj + +/src/java/workspace/UITest +/src/java/JavaFileStorage/bin +/src/java/JavaFileStorage/gen/keepass2android/javafilestorage/BuildConfig.java +/src/java/JavaFileStorage/gen/keepass2android/javafilestorage/R.java +/src/JavaFileStorageBindings/bin/Debug +/src/JavaFileStorageBindings/bin/Release +/src/JavaFileStorageBindings/obj/Debug +/src/JavaFileStorageBindings/obj/Release +/src/JavaFileStorageTest +/src/java/workspace/DBRoulette +/src/java/workspace/JavaFileStorageTest +/src/java/JavaFileStorage/src/keepass2android/javafilestorage/SecretKeys.java diff --git a/src/JavaFileStorageBindings/Additions/AboutAdditions.txt b/src/JavaFileStorageBindings/Additions/AboutAdditions.txt new file mode 100644 index 00000000..08caee33 --- /dev/null +++ b/src/JavaFileStorageBindings/Additions/AboutAdditions.txt @@ -0,0 +1,48 @@ +Additions allow you to add arbitrary C# to the generated classes +before they are compiled. This can be helpful for providing convenience +methods or adding pure C# classes. + +== Adding Methods to Generated Classes == + +Let's say the library being bound has a Rectangle class with a constructor +that takes an x and y position, and a width and length size. It will look like +this: + +public partial class Rectangle +{ + public Rectangle (int x, int y, int width, int height) + { + // JNI bindings + } +} + +Imagine we want to add a constructor to this class that takes a Point and +Size structure instead of 4 ints. We can add a new file called Rectangle.cs +with a partial class containing our new method: + +public partial class Rectangle +{ + public Rectangle (Point location, Size size) : + this (location.X, location.Y, size.Width, size.Height) + { + } +} + +At compile time, the additions class will be added to the generated class +and the final assembly will a Rectangle class with both constructors. + + +== Adding C# Classes == + +Another thing that can be done is adding fully C# managed classes to the +generated library. In the above example, let's assume that there isn't a +Point class available in Java or our library. The one we create doesn't need +to interact with Java, so we'll create it like a normal class in C#. + +By adding a Point.cs file with this class, it will end up in the binding library: + +public class Point +{ + public int X { get; set; } + public int Y { get; set; } +} \ No newline at end of file diff --git a/src/JavaFileStorageBindings/Jars/AboutJars.txt b/src/JavaFileStorageBindings/Jars/AboutJars.txt new file mode 100644 index 00000000..c359b62f --- /dev/null +++ b/src/JavaFileStorageBindings/Jars/AboutJars.txt @@ -0,0 +1,24 @@ +This directory is for Android .jars. + +There are 2 types of jars that are supported: + +== Input Jar == + +This is the jar that bindings should be generated for. + +For example, if you were binding the Google Maps library, this would +be Google's "maps.jar". + +Set the build action for these jars in the properties page to "InputJar". + + +== Reference Jars == + +These are jars that are referenced by the input jar. C# bindings will +not be created for these jars. These jars will be used to resolve +types used by the input jar. + +NOTE: Do not add "android.jar" as a reference jar. It will be added automatically +based on the Target Framework selected. + +Set the build action for these jars in the properties page to "ReferenceJar". \ No newline at end of file diff --git a/src/JavaFileStorageBindings/JavaFileStorageBindings.csproj b/src/JavaFileStorageBindings/JavaFileStorageBindings.csproj new file mode 100644 index 00000000..d9d0dfb2 --- /dev/null +++ b/src/JavaFileStorageBindings/JavaFileStorageBindings.csproj @@ -0,0 +1,84 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {48574278-4779-4B3A-A9E4-9CF1BC285D0B} + {10368E6C-D01B-4462-8E8B-01FC667A7035};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Properties + JavaFileStorageBindings + JavaFileStorageBindings + 512 + v2.2 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + Jars\javafilestorage.jar + + + + + Jars\android-support-v4.jar + + + + + Jars\dropbox-android-sdk-1.5.4.jar + + + + + Jars\httpmime-4.0.3.jar + + + + + Jars\json_simple-1.1.jar + + + + + \ No newline at end of file diff --git a/src/JavaFileStorageBindings/Properties/AssemblyInfo.cs b/src/JavaFileStorageBindings/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..c49cfd29 --- /dev/null +++ b/src/JavaFileStorageBindings/Properties/AssemblyInfo.cs @@ -0,0 +1,34 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Android.App; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JavaFileStorageBindings")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JavaFileStorageBindings")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +// Add some common permissions, these can be removed if not needed +[assembly: UsesPermission(Android.Manifest.Permission.Internet)] +[assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)] diff --git a/src/JavaFileStorageBindings/Transforms/EnumFields.xml b/src/JavaFileStorageBindings/Transforms/EnumFields.xml new file mode 100644 index 00000000..22959957 --- /dev/null +++ b/src/JavaFileStorageBindings/Transforms/EnumFields.xml @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/src/JavaFileStorageBindings/Transforms/EnumMethods.xml b/src/JavaFileStorageBindings/Transforms/EnumMethods.xml new file mode 100644 index 00000000..49216c61 --- /dev/null +++ b/src/JavaFileStorageBindings/Transforms/EnumMethods.xml @@ -0,0 +1,13 @@ + + + \ No newline at end of file diff --git a/src/JavaFileStorageBindings/Transforms/Metadata.xml b/src/JavaFileStorageBindings/Transforms/Metadata.xml new file mode 100644 index 00000000..2587ddc4 --- /dev/null +++ b/src/JavaFileStorageBindings/Transforms/Metadata.xml @@ -0,0 +1,9 @@ + + + diff --git a/src/KeePass.sln b/src/KeePass.sln index c0b6a9f6..9342928d 100644 --- a/src/KeePass.sln +++ b/src/KeePass.sln @@ -17,6 +17,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kp2aUnitTests", "Kp2aUnitTe EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TwofishCipher", "TwofishCipher\TwofishCipher.csproj", "{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JavaFileStorageBindings", "JavaFileStorageBindings\JavaFileStorageBindings.csproj", "{48574278-4779-4B3A-A9E4-9CF1BC285D0B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -202,6 +204,24 @@ Global {5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU {5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU {5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Win32.ActiveCfg = Debug|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|x64.ActiveCfg = Debug|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Any CPU.Build.0 = Release|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Win32.ActiveCfg = Release|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|x64.ActiveCfg = Release|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU + {48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs b/src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs index da2a2553..c5f2b370 100644 --- a/src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/BuiltInFileStorage.cs @@ -19,6 +19,17 @@ namespace keepass2android.Io { public class BuiltInFileStorage: IFileStorage { + public IEnumerable SupportedProtocols + { + get + { + yield return "file"; + yield return "ftp"; + yield return "http"; + yield return "https"; + } + } + public void DeleteFile(IOConnectionInfo ioc) { IOConnection.DeleteFile(ioc); @@ -78,6 +89,8 @@ namespace keepass2android.Io return new BuiltInFileTransaction(ioc, useFileTransaction); } + public IFileStorageSetup RequiredSetup { get { return null; } } + public class BuiltInFileTransaction : IWriteTransaction { private readonly FileTransactionEx _transaction; @@ -119,5 +132,10 @@ namespace keepass2android.Io UrlUtil.GetFileName(ioc.Path)); } + + public bool RequiresCredentials(IOConnectionInfo ioc) + { + return (!ioc.IsLocalFile()) && (ioc.CredSaveMode != IOCredSaveMode.SaveCred); + } } } \ No newline at end of file diff --git a/src/Kp2aBusinessLogic/Io/CachingFileStorage.cs b/src/Kp2aBusinessLogic/Io/CachingFileStorage.cs index 508c73ea..b96135a5 100644 --- a/src/Kp2aBusinessLogic/Io/CachingFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/CachingFileStorage.cs @@ -77,6 +77,8 @@ namespace keepass2android.Io IoUtil.DeleteDir(new Java.IO.File(_streamCacheDir), true); } + public IEnumerable SupportedProtocols { get { return _cachedStorage.SupportedProtocols; } } + public void DeleteFile(IOConnectionInfo ioc) { if (IsCached(ioc)) @@ -391,6 +393,8 @@ namespace keepass2android.Io return new CachedWriteTransaction(ioc, useFileTransaction, this); } + public IFileStorageSetup RequiredSetup { get { return _cachedStorage.RequiredSetup; } } + public bool CompleteIoId() { throw new NotImplementedException(); @@ -407,6 +411,11 @@ namespace keepass2android.Io UrlUtil.GetFileName(ioc.Path)); } + public bool RequiresCredentials(IOConnectionInfo ioc) + { + return _cachedStorage.RequiresCredentials(ioc); + } + public string GetBaseVersionHash(IOConnectionInfo ioc) { diff --git a/src/Kp2aBusinessLogic/Io/DropboxFileStorage.cs b/src/Kp2aBusinessLogic/Io/DropboxFileStorage.cs new file mode 100644 index 00000000..634f2692 --- /dev/null +++ b/src/Kp2aBusinessLogic/Io/DropboxFileStorage.cs @@ -0,0 +1,27 @@ +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.Serialization; +using Keepass2android.Javafilestorage; + +namespace keepass2android.Io +{ + public class DropboxFileStorage: JavaFileStorage + { + public DropboxFileStorage(Context ctx) : + base(new Keepass2android.Javafilestorage.DropboxFileStorage(ctx)) + { + } + + public override IEnumerable SupportedProtocols { get { yield return "dropbox"; } } + } +} \ No newline at end of file diff --git a/src/Kp2aBusinessLogic/Io/GDriveFileStorage.cs b/src/Kp2aBusinessLogic/Io/GDriveFileStorage.cs new file mode 100644 index 00000000..fd3e49ea --- /dev/null +++ b/src/Kp2aBusinessLogic/Io/GDriveFileStorage.cs @@ -0,0 +1,67 @@ +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.Serialization; + +namespace keepass2android.Io +{ + public class GDriveFileStorage: IFileStorage + { + public IEnumerable SupportedProtocols { get { yield return "gdrive"; } } + public void DeleteFile(IOConnectionInfo ioc) + { + throw new NotImplementedException(); + } + + public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion) + { + throw new NotImplementedException(); + } + + public string GetCurrentFileVersionFast(IOConnectionInfo ioc) + { + throw new NotImplementedException(); + } + + public Stream OpenFileForRead(IOConnectionInfo ioc) + { + throw new NotImplementedException(); + } + + public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction) + { + throw new NotImplementedException(); + } + + public IFileStorageSetup RequiredSetup { get; private set; } + + public bool CompleteIoId() + { + throw new NotImplementedException(); + } + + public bool? FileExists() + { + throw new NotImplementedException(); + } + + public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc) + { + throw new NotImplementedException(); + } + + public bool RequiresCredentials(IOConnectionInfo ioc) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Kp2aBusinessLogic/Io/IFileStorage.cs b/src/Kp2aBusinessLogic/Io/IFileStorage.cs index 91cf972c..a3a90402 100644 --- a/src/Kp2aBusinessLogic/Io/IFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/IFileStorage.cs @@ -33,6 +33,8 @@ namespace keepass2android.Io /// have an IIoStorageId interface in few cases.*/ public interface IFileStorage { + IEnumerable SupportedProtocols { get; } + /// /// Deletes the given file. /// @@ -55,10 +57,26 @@ namespace keepass2android.Io /// A string which should not be null. string GetCurrentFileVersionFast(IOConnectionInfo ioc); + /// + /// Opens the given file for reading + /// Stream OpenFileForRead(IOConnectionInfo ioc); - //Stream OpenFileForWrite( IOConnectionInfo ioc, bool useTransaction); + + /// + /// Opens a write transaction for writing to the given ioc. + /// + /// ioc to write to + /// if true, force to use file system level transaction. This might be ignored if the file storage has built in transaction support IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction); + /// + /// Returns an instance of an implementation of IFileStorageSetup or one of the more complex interfaces. + /// Depending on the type returned, the caller should try to follow the interface as close as possible. + /// Returns null if the file storage is setup or doesn't require anything to work. + /// + /// This is due to different storage types requiring different workflows for authentication processes + IFileStorageSetup RequiredSetup { get; } + /// /// brings up a dialog to query credentials or something like this. /// @@ -73,6 +91,37 @@ namespace keepass2android.Io bool? FileExists( /*ioId*/); string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc); + + /// + /// Returns true if the the given ioc must be filled with username/password + /// + bool RequiresCredentials(IOConnectionInfo ioc); + } + + /// + /// Base interface for required setup code + /// + public interface IFileStorageSetup + { + /// + /// call this when the user explicitly wants to use this file storage. Might require user interaction. + /// May throw if the setup failed permanentaly. + /// + /// true if the setup was succesful immediately (without UI). Returns false if setup was not successful but no error occured or can be displayed. + bool TrySetup(Activity activity); + } + + /// + /// Interface which can be used additionally for an IFileStorageSetup to indicate that setup must be completed in OnResume() + /// + public interface IFileStorageSetupOnResume + { + /// + /// call this after TrySetup() returned false in the next OnResume() + /// May throw if the setup failed permanentaly. + /// + /// true if setup was succesful + bool TrySetupOnResume(Activity activity); } public interface IWriteTransaction: IDisposable diff --git a/src/Kp2aBusinessLogic/Io/JavaFileStorage.cs b/src/Kp2aBusinessLogic/Io/JavaFileStorage.cs new file mode 100644 index 00000000..40f9ea5e --- /dev/null +++ b/src/Kp2aBusinessLogic/Io/JavaFileStorage.cs @@ -0,0 +1,207 @@ +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 Java.Lang; +using KeePassLib.Serialization; +using KeePassLib.Utility; +using Keepass2android.Javafilestorage; +using Exception = System.Exception; + +namespace keepass2android.Io +{ + public abstract class JavaFileStorage: IFileStorage + { + public abstract IEnumerable SupportedProtocols { get; } + + private IJavaFileStorage _jfs; + + public JavaFileStorage(IJavaFileStorage jfs) + { + this._jfs = jfs; + } + + public void DeleteFile(IOConnectionInfo ioc) + { + throw new NotImplementedException(); + } + + public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion) + { + try + { + return _jfs.CheckForFileChangeFast(ioc.Path, previousFileVersion); + } + catch (Java.Lang.Exception e) + { + Kp2aLog.Log(e.Message); + throw new Exception(e.Message, e); + } + + } + + public string GetCurrentFileVersionFast(IOConnectionInfo ioc) + { + try + { + return _jfs.GetCurrentFileVersionFast(ioc.Path); + } + catch (Java.Lang.Exception e) + { + Kp2aLog.Log(e.Message); + throw new Exception(e.Message, e); + } + } + + public Stream OpenFileForRead(IOConnectionInfo ioc) + { + try + { + return _jfs.OpenFileForRead(IocToPath(ioc)); + } + catch (Java.IO.FileNotFoundException e) + { + throw new System.IO.FileNotFoundException(e.Message, e); + } + catch (Java.Lang.Exception e) + { + Kp2aLog.Log(e.Message); + throw new Exception(e.Message, e); + } + + } + + public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction) + { + return new JavaFileStorageWriteTransaction(IocToPath(ioc), useFileTransaction, _jfs); + } + + public IFileStorageSetup RequiredSetup + { + get + { + if (_jfs.IsConnected) + return null; + return new JavaFileStorageSetup(this); + } + } + + public class JavaFileStorageSetup : IFileStorageSetup, IFileStorageSetupOnResume + { + private readonly JavaFileStorage _javaFileStorage; + + public JavaFileStorageSetup(JavaFileStorage javaFileStorage) + { + _javaFileStorage = javaFileStorage; + } + + public bool TrySetup(Activity activity) + { + try + { + return _javaFileStorage._jfs.TryConnect(activity); + } + catch (Java.Lang.Exception e) + { + Kp2aLog.Log(e.Message); + throw new Exception(e.Message, e); + } + } + + public bool TrySetupOnResume(Activity activity) + { + try + { + _javaFileStorage._jfs.OnResume(); + return _javaFileStorage._jfs.IsConnected; + } + catch (Java.Lang.Exception e) + { + Kp2aLog.Log(e.Message); + throw new Exception(e.Message, e); + } + + } + } + + class JavaFileStorageWriteTransaction: IWriteTransaction + { + private readonly string _path; + private readonly bool _useFileTransaction; + private readonly IJavaFileStorage _javaFileStorage; + private MemoryStream _memoryStream; + + public JavaFileStorageWriteTransaction(string path, bool useFileTransaction, IJavaFileStorage javaFileStorage) + { + _path = path; + _useFileTransaction = useFileTransaction; + _javaFileStorage = javaFileStorage; + } + + public void Dispose() + { + _memoryStream.Dispose(); + } + + public Stream OpenFile() + { + _memoryStream = new MemoryStream(); + return _memoryStream; + } + + public void CommitWrite() + { + try + { + _javaFileStorage.UploadFile(_path, _memoryStream.ToArray(), _useFileTransaction); + } + catch (Java.Lang.Exception e) + { + Kp2aLog.Log(e.ToString()); + throw new Exception(e.Message, e); + } + } + } + + public bool CompleteIoId() + { + throw new NotImplementedException(); + } + + public bool? FileExists() + { + throw new NotImplementedException(); + } + + public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc) + { + return UrlUtil.StripExtension( + UrlUtil.GetFileName(IocToPath(ioc))); + } + + public bool RequiresCredentials(IOConnectionInfo ioc) + { + return false; + } + + private static string IocToPath(IOConnectionInfo ioc) + { + int protocolLength = ioc.Path.IndexOf("://", System.StringComparison.Ordinal); + + if (protocolLength < 0) + return ioc.Path; + else + return ioc.Path.Substring(protocolLength + 3); + } + + + } +} \ No newline at end of file diff --git a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj index 255fa70e..b4ea8a6a 100644 --- a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj +++ b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj @@ -57,8 +57,11 @@ + + + @@ -89,6 +92,10 @@ + + {48574278-4779-4b3a-a9e4-9cf1bc285d0b} + JavaFileStorageBindings + {545b4a6b-8bba-4fbe-92fc-4ac060122a54} KeePassLib2Android diff --git a/src/Kp2aUnitTests/TestFileStorage.cs b/src/Kp2aUnitTests/TestFileStorage.cs index ed70ee3c..9dcf2727 100644 --- a/src/Kp2aUnitTests/TestFileStorage.cs +++ b/src/Kp2aUnitTests/TestFileStorage.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using KeePassLib.Serialization; using keepass2android.Io; @@ -11,6 +12,7 @@ namespace Kp2aUnitTests public bool Offline { get; set; } + public IEnumerable SupportedProtocols { get { yield return "test"; } } public void DeleteFile(IOConnectionInfo ioc) { @@ -19,6 +21,8 @@ namespace Kp2aUnitTests _builtIn.DeleteFile(ioc); } + public IFileStorageSetup RequiredSetup { get { return null; } } + public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion) { if (Offline) @@ -92,5 +96,10 @@ namespace Kp2aUnitTests { return _builtIn.GetFilenameWithoutPathAndExt(ioc); } + + public bool RequiresCredentials(IOConnectionInfo ioc) + { + return _builtIn.RequiresCredentials(ioc); + } } } \ No newline at end of file diff --git a/src/java/JavaFileStorage/.classpath b/src/java/JavaFileStorage/.classpath new file mode 100644 index 00000000..2731f9c5 --- /dev/null +++ b/src/java/JavaFileStorage/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/java/JavaFileStorage/.project b/src/java/JavaFileStorage/.project new file mode 100644 index 00000000..32ed6251 --- /dev/null +++ b/src/java/JavaFileStorage/.project @@ -0,0 +1,33 @@ + + + JavaFileStorage + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/src/java/JavaFileStorage/.settings/org.eclipse.jdt.core.prefs b/src/java/JavaFileStorage/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..b080d2dd --- /dev/null +++ b/src/java/JavaFileStorage/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/src/java/JavaFileStorage/AndroidManifest.xml b/src/java/JavaFileStorage/AndroidManifest.xml new file mode 100644 index 00000000..4b9c3feb --- /dev/null +++ b/src/java/JavaFileStorage/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + diff --git a/src/java/JavaFileStorage/libs/HTTPCOMPONENTS-LICENSE.txt b/src/java/JavaFileStorage/libs/HTTPCOMPONENTS-LICENSE.txt new file mode 100644 index 00000000..2c41ec88 --- /dev/null +++ b/src/java/JavaFileStorage/libs/HTTPCOMPONENTS-LICENSE.txt @@ -0,0 +1,182 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + +This project contains annotations derived from JCIP-ANNOTATIONS +Copyright (c) 2005 Brian Goetz and Tim Peierls. +See http://www.jcip.net and the Creative Commons Attribution License +(http://creativecommons.org/licenses/by/2.5) + diff --git a/src/java/JavaFileStorage/libs/JSON-SIMPLE-LICENSE.txt b/src/java/JavaFileStorage/libs/JSON-SIMPLE-LICENSE.txt new file mode 100644 index 00000000..57bc88a1 --- /dev/null +++ b/src/java/JavaFileStorage/libs/JSON-SIMPLE-LICENSE.txt @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/src/java/JavaFileStorage/libs/android-support-v4.jar b/src/java/JavaFileStorage/libs/android-support-v4.jar new file mode 100644 index 00000000..428bdbc0 Binary files /dev/null and b/src/java/JavaFileStorage/libs/android-support-v4.jar differ diff --git a/src/java/JavaFileStorage/libs/dropbox-android-sdk-1.5.4.jar b/src/java/JavaFileStorage/libs/dropbox-android-sdk-1.5.4.jar new file mode 100644 index 00000000..38a3602f Binary files /dev/null and b/src/java/JavaFileStorage/libs/dropbox-android-sdk-1.5.4.jar differ diff --git a/src/java/JavaFileStorage/libs/httpmime-4.0.3.jar b/src/java/JavaFileStorage/libs/httpmime-4.0.3.jar new file mode 100644 index 00000000..0dfd3312 Binary files /dev/null and b/src/java/JavaFileStorage/libs/httpmime-4.0.3.jar differ diff --git a/src/java/JavaFileStorage/libs/json_simple-1.1.jar b/src/java/JavaFileStorage/libs/json_simple-1.1.jar new file mode 100644 index 00000000..f395f414 Binary files /dev/null and b/src/java/JavaFileStorage/libs/json_simple-1.1.jar differ diff --git a/src/java/JavaFileStorage/proguard-project.txt b/src/java/JavaFileStorage/proguard-project.txt new file mode 100644 index 00000000..f2fe1559 --- /dev/null +++ b/src/java/JavaFileStorage/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/src/java/JavaFileStorage/project.properties b/src/java/JavaFileStorage/project.properties new file mode 100644 index 00000000..484dab07 --- /dev/null +++ b/src/java/JavaFileStorage/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-17 +android.library=true diff --git a/src/java/JavaFileStorage/res/drawable-hdpi/ic_launcher.png b/src/java/JavaFileStorage/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 00000000..96a442e5 Binary files /dev/null and b/src/java/JavaFileStorage/res/drawable-hdpi/ic_launcher.png differ diff --git a/src/java/JavaFileStorage/res/drawable-mdpi/ic_launcher.png b/src/java/JavaFileStorage/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 00000000..359047df Binary files /dev/null and b/src/java/JavaFileStorage/res/drawable-mdpi/ic_launcher.png differ diff --git a/src/java/JavaFileStorage/res/drawable-xhdpi/ic_launcher.png b/src/java/JavaFileStorage/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 00000000..71c6d760 Binary files /dev/null and b/src/java/JavaFileStorage/res/drawable-xhdpi/ic_launcher.png differ diff --git a/src/java/JavaFileStorage/res/values-v11/styles.xml b/src/java/JavaFileStorage/res/values-v11/styles.xml new file mode 100644 index 00000000..3c02242a --- /dev/null +++ b/src/java/JavaFileStorage/res/values-v11/styles.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/java/JavaFileStorage/res/values-v14/styles.xml b/src/java/JavaFileStorage/res/values-v14/styles.xml new file mode 100644 index 00000000..a91fd037 --- /dev/null +++ b/src/java/JavaFileStorage/res/values-v14/styles.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/src/java/JavaFileStorage/res/values/strings.xml b/src/java/JavaFileStorage/res/values/strings.xml new file mode 100644 index 00000000..51a5f8cc --- /dev/null +++ b/src/java/JavaFileStorage/res/values/strings.xml @@ -0,0 +1,5 @@ + + + JavaFileStorage + + diff --git a/src/java/JavaFileStorage/res/values/styles.xml b/src/java/JavaFileStorage/res/values/styles.xml new file mode 100644 index 00000000..6ce89c7b --- /dev/null +++ b/src/java/JavaFileStorage/res/values/styles.xml @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/src/java/JavaFileStorage/src/keepass2android/javafilestorage/DropboxFileStorage.java b/src/java/JavaFileStorage/src/keepass2android/javafilestorage/DropboxFileStorage.java new file mode 100644 index 00000000..d5a3fa69 --- /dev/null +++ b/src/java/JavaFileStorage/src/keepass2android/javafilestorage/DropboxFileStorage.java @@ -0,0 +1,268 @@ +package keepass2android.javafilestorage; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.ArrayList; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.DropBoxManager.Entry; +import android.util.Log; +import android.widget.Toast; + +import com.dropbox.client2.DropboxAPI; +import com.dropbox.client2.android.AndroidAuthSession; +import com.dropbox.client2.android.AuthActivity; +import com.dropbox.client2.exception.DropboxException; +import com.dropbox.client2.exception.DropboxServerException; +import com.dropbox.client2.session.AccessTokenPair; +import com.dropbox.client2.session.AppKeyPair; +import com.dropbox.client2.session.TokenPair; +import com.dropbox.client2.session.Session.AccessType; + + + +public class DropboxFileStorage implements JavaFileStorage { + final static private String APP_KEY = "i8shu7v1hgh7ynt"; + + // If you'd like to change the access type to the full Dropbox instead of + // an app folder, change this value. + final static private AccessType ACCESS_TYPE = AccessType.DROPBOX; + + final static private String TAG = "KP2AJ"; + + final static private String ACCOUNT_PREFS_NAME = "prefs"; + final static private String ACCESS_KEY_NAME = "ACCESS_KEY"; + final static private String ACCESS_SECRET_NAME = "ACCESS_SECRET"; + + + + DropboxAPI mApi; + private boolean mLoggedIn = false; + private Context mContext; + + public DropboxFileStorage(Context ctx) + { + mContext = ctx; + // We create a new AuthSession so that we can use the Dropbox API. + AndroidAuthSession session = buildSession(); + mApi = new DropboxAPI(session); + + checkAppKeySetup(); + } + + public boolean tryConnect(Activity activity) + { + if (!mLoggedIn) + mApi.getSession().startAuthentication(activity); + return mLoggedIn; + } + + public void onResume() + { + AndroidAuthSession session = mApi.getSession(); + + // The next part must be inserted in the onResume() method of the + // activity from which session.startAuthentication() was called, so + // that Dropbox authentication completes properly. + if (session.authenticationSuccessful()) { + try { + // Mandatory call to complete the auth + session.finishAuthentication(); + + // Store it locally in our app for later use + TokenPair tokens = session.getAccessTokenPair(); + storeKeys(tokens.key, tokens.secret); + setLoggedIn(true); + } catch (IllegalStateException e) { + showToast("Couldn't authenticate with Dropbox:" + e.getLocalizedMessage()); + Log.i(TAG, "Error authenticating", e); + } + } + } + + private void setLoggedIn(boolean b) { + mLoggedIn = b; + + } + + private boolean checkAppKeySetup() { + + // Check if the app has set up its manifest properly. + Intent testIntent = new Intent(Intent.ACTION_VIEW); + String scheme = "db-" + APP_KEY; + String uri = scheme + "://" + AuthActivity.AUTH_VERSION + "/test"; + testIntent.setData(Uri.parse(uri)); + PackageManager pm = mContext.getPackageManager(); + if (0 == pm.queryIntentActivities(testIntent, 0).size()) { + showToast("URL scheme in your app's " + + "manifest is not set up correctly. You should have a " + + "com.dropbox.client2.android.AuthActivity with the " + + "scheme: " + scheme); + return false; + } + return true; + } + + public boolean isConnected() + { + return mLoggedIn; + } + + public ArrayList listContents(String path) throws Exception + { + ArrayList files = new ArrayList(); + try { + DropboxAPI.Entry existingEntry = mApi.metadata(path, 0, null, true, null); + for (DropboxAPI.Entry ent: existingEntry.contents) + { + files.add(ent.path); + + } + // do stuff with the Entry + } catch (DropboxException e) { + throw getNonDropboxException(e); + } + return files; + } + + public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception + { + if ((previousFileVersion == null) || (previousFileVersion == "")) + return false; + try { + com.dropbox.client2.DropboxAPI.Entry entry = mApi.metadata(path, 1, null, false, null); + return entry.hash != previousFileVersion; + } catch (DropboxException e) { + throw getNonDropboxException(e); + } + } + + public String getCurrentFileVersionFast(String path) + { + try { + com.dropbox.client2.DropboxAPI.Entry entry = mApi.metadata(path, 1, null, false, null); + return entry.rev; + } catch (DropboxException e) { + Log.d(TAG, e.toString()); + return ""; + } + } + + public InputStream openFileForRead(String path) throws Exception + { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + try { + return mApi.getFileStream(path, null); + } catch (DropboxException e) { + //System.out.println("Something went wrong: " + e); + throw getNonDropboxException(e); + } + } + + public void uploadFile(String path, byte[] data, boolean writeTransactional) throws Exception + { + ByteArrayInputStream bis = new ByteArrayInputStream(data); + try { + //TODO: it would be nice to be able to use the parent version with putFile() + mApi.putFileOverwrite(path, bis, data.length, null); + } catch (DropboxException e) { + throw getNonDropboxException(e); + } + } + + private Exception getNonDropboxException(DropboxException e) { + + //TODO test for special error codes like 404 + Log.d(TAG, "Exception of type " +e.getClass().getName()+":" + e.getMessage()); + + if (DropboxServerException.class.isAssignableFrom(e.getClass()) ) + { + + DropboxServerException serverEx = (DropboxServerException)e; + if (serverEx.error == 404) + return new FileNotFoundException(e.toString()); + } + + return e; + //return new Exception(e.toString()); + + } + + private void showToast(String msg) { + Toast error = Toast.makeText(mContext, msg, Toast.LENGTH_LONG); + error.show(); + } + + /** + * Keep the access keys returned from Trusted Authenticator in a local + * store, rather than storing user name & password, and re-authenticating each + * time (which is not to be done, ever). + * + * @return Array of [access_key, access_secret], or null if none stored + */ + private String[] getKeys() { + SharedPreferences prefs = mContext.getSharedPreferences(ACCOUNT_PREFS_NAME, 0); + String key = prefs.getString(ACCESS_KEY_NAME, null); + String secret = prefs.getString(ACCESS_SECRET_NAME, null); + if (key != null && secret != null) { + String[] ret = new String[2]; + ret[0] = key; + ret[1] = secret; + return ret; + } else { + return null; + } + } + + /** + * Keeping the access keys returned from Trusted Authenticator in a local + * store, rather than storing user name & password, and re-authenticating each + * time (which is not to be done, ever). + */ + private void storeKeys(String key, String secret) { + Log.d(TAG, "Storing Dropbox accessToken"); + // Save the access key for later + SharedPreferences prefs = mContext.getSharedPreferences(ACCOUNT_PREFS_NAME, 0); + Editor edit = prefs.edit(); + edit.putString(ACCESS_KEY_NAME, key); + edit.putString(ACCESS_SECRET_NAME, secret); + edit.commit(); + } + + //TODO: call when Unlinked Exception + private void clearKeys() { + SharedPreferences prefs = mContext.getSharedPreferences(ACCOUNT_PREFS_NAME, 0); + Editor edit = prefs.edit(); + edit.clear(); + edit.commit(); + } + + private AndroidAuthSession buildSession() { + //note: the SecretKeys class is not public because the App-Secret must be secret! + AppKeyPair appKeyPair = new AppKeyPair(APP_KEY, SecretKeys.DROPBOX_APP_SECRET); + AndroidAuthSession session; + + String[] stored = getKeys(); + if (stored != null) { + AccessTokenPair accessToken = new AccessTokenPair(stored[0], stored[1]); + session = new AndroidAuthSession(appKeyPair, ACCESS_TYPE, accessToken); + setLoggedIn(true); + Log.d(TAG, "Creating Dropbox Session with accessToken"); + } else { + session = new AndroidAuthSession(appKeyPair, ACCESS_TYPE); + setLoggedIn(false); + Log.d(TAG, "Creating Dropbox Session without accessToken"); + } + + return session; + } + +} diff --git a/src/java/JavaFileStorage/src/keepass2android/javafilestorage/JavaFileStorage.java b/src/java/JavaFileStorage/src/keepass2android/javafilestorage/JavaFileStorage.java new file mode 100644 index 00000000..588ea0f0 --- /dev/null +++ b/src/java/JavaFileStorage/src/keepass2android/javafilestorage/JavaFileStorage.java @@ -0,0 +1,22 @@ +package keepass2android.javafilestorage; + +import java.io.InputStream; +import android.app.Activity; + +public interface JavaFileStorage { + public boolean tryConnect(Activity activity); + + public void onResume(); + + + public boolean isConnected(); + + + public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception; + + public String getCurrentFileVersionFast(String path); + + public InputStream openFileForRead(String path) throws Exception; + + public void uploadFile(String path, byte[] data, boolean writeTransactional) throws Exception; +} \ No newline at end of file diff --git a/src/keepass2android/FileStorageSelectionActivity.cs b/src/keepass2android/FileStorageSelectionActivity.cs new file mode 100644 index 00000000..48c47864 --- /dev/null +++ b/src/keepass2android/FileStorageSelectionActivity.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Android.App; +using Android.Content; +using Android.Content.PM; +using Android.Graphics.Drawables; +using Android.OS; +using Android.Runtime; +using Android.Views; +using Android.Widget; +using keepass2android.Io; +using Object = Java.Lang.Object; + +namespace keepass2android +{ + [Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden , Theme="@style/NoTitleBar")] + public class FileStorageSelectionActivity : ListActivity + { + private string _protocolToSetup; + + class FileStorageAdapter: BaseAdapter + { + private readonly FileStorageSelectionActivity _context; + + private List _protocolIds = new List(); + + public FileStorageAdapter(FileStorageSelectionActivity context) + { + _context = context; + //show all supported protocols: + foreach (IFileStorage fs in App.Kp2a.FileStorages) + _protocolIds.AddRange(fs.SupportedProtocols); + //except file:// + _protocolIds.Remove("file"); + } + + public override Object GetItem(int position) + { + return position; + } + + public override long GetItemId(int position) + { + return position; + } + + public override View GetView(int position, View convertView, ViewGroup parent) + { + LayoutInflater inflater = (LayoutInflater)_context.GetSystemService(LayoutInflaterService); + View v = inflater.Inflate(Resource.Layout.filestorage_selection_listitem, null); + ((TextView)v.FindViewById(Resource.Id.filestorage_label)).Text = + App.Kp2a.GetResourceString("filestoragename_"+_protocolIds[position] ); + Drawable drawable = App.Kp2a.GetResourceDrawable("ic_storage_" + _protocolIds[position]); + ((ImageView)v.FindViewById(Resource.Id.filestorage_logo)).SetImageDrawable(drawable); + v.Click += (sender, args) => _context.OnItemSelected(_protocolIds[position]); + return v; + } + + public override int Count + { + get { return _protocolIds.Count; } + } + } + + private void OnItemSelected(string protocolId) + { + var fs = App.Kp2a.GetFileStorage(protocolId); + IFileStorageSetup fssetup = fs.RequiredSetup; + try + { + if ((fssetup == null) || (fssetup.TrySetup(this))) + { + ReturnProtocol(protocolId); + } + else + { + //setup not yet complete + _protocolToSetup = protocolId; + } + } + catch (Exception e) + { + Toast.MakeText(this, e.Message, ToastLength.Long).Show(); + } + + } + + private void ReturnProtocol(string protocolId) + { + Intent intent = new Intent(); + intent.PutExtra("protocolId", protocolId); + SetResult(KeePass.ExitFileStorageSelectionOk, intent); + Finish(); + } + + protected override void OnCreate(Bundle bundle) + { + base.OnCreate(bundle); + + if (bundle != null) + _protocolToSetup = bundle.GetString("_protocolToSetup", null); + + SetContentView(Resource.Layout.filestorage_selection); + + this.ListAdapter = new FileStorageAdapter(this); + + + } + + protected override void OnSaveInstanceState(Bundle outState) + { + base.OnSaveInstanceState(outState); + outState.PutString("_protocolToSetup",_protocolToSetup); + } + + protected override void OnResume() + { + base.OnResume(); + if (!String.IsNullOrEmpty(_protocolToSetup)) + { + try + { + string protocolToSetup = _protocolToSetup; + _protocolToSetup = null; + + IFileStorageSetupOnResume fsSetup = App.Kp2a.GetFileStorage(protocolToSetup).RequiredSetup as IFileStorageSetupOnResume; + if ((fsSetup == null) || (fsSetup.TrySetupOnResume(this))) + { + ReturnProtocol(protocolToSetup); + } + + } + catch (Exception e) + { + Toast.MakeText(this, e.Message, ToastLength.Long).Show(); + } + } + } + } +} \ No newline at end of file diff --git a/src/keepass2android/KeePass.cs b/src/keepass2android/KeePass.cs index 8167eb13..92e5e481 100644 --- a/src/keepass2android/KeePass.cs +++ b/src/keepass2android/KeePass.cs @@ -42,6 +42,7 @@ namespace keepass2android public const Result TaskComplete = Result.FirstUser + 5; public const Result ExitReloadDb = Result.FirstUser+6; public const Result ExitClose = Result.FirstUser + 7; + public const Result ExitFileStorageSelectionOk = Result.FirstUser + 8; AppTask _appTask; @@ -110,6 +111,8 @@ namespace keepass2android private void LaunchNextActivity() { + + if (!App.Kp2a.GetDb().Loaded) { // Load default database @@ -144,7 +147,7 @@ namespace keepass2android StartActivityForResult(intent, 0); Finish(); - + } diff --git a/src/keepass2android/PasswordActivity.cs b/src/keepass2android/PasswordActivity.cs index 7bc97e25..ef9a3525 100644 --- a/src/keepass2android/PasswordActivity.cs +++ b/src/keepass2android/PasswordActivity.cs @@ -105,12 +105,6 @@ namespace keepass2android } - public static void Launch(Activity act, String fileName) { - Launch(act, IOConnectionInfo.FromPath(fileName), null); - - } - - public static void Launch(Activity act, IOConnectionInfo ioc, AppTask appTask) { if (ioc.IsLocalFile()) diff --git a/src/keepass2android/Properties/AndroidManifest_net.xml b/src/keepass2android/Properties/AndroidManifest_net.xml index 333821da..f58af94c 100644 --- a/src/keepass2android/Properties/AndroidManifest_net.xml +++ b/src/keepass2android/Properties/AndroidManifest_net.xml @@ -6,6 +6,19 @@ android:installLocation="auto"> + + + + + + + + + + diff --git a/src/keepass2android/Resources/Resource.designer.cs b/src/keepass2android/Resources/Resource.designer.cs index 057fc203..c76147fc 100644 --- a/src/keepass2android/Resources/Resource.designer.cs +++ b/src/keepass2android/Resources/Resource.designer.cs @@ -512,70 +512,85 @@ namespace keepass2android public const int ic_menu_view = 2130837595; // aapt resource value: 0x7f02005c - public const int ic_unlocked_gray = 2130837596; + public const int ic_storage_dropbox = 2130837596; // aapt resource value: 0x7f02005d - public const int location_web_site = 2130837597; + public const int ic_storage_ftp = 2130837597; // aapt resource value: 0x7f02005e - public const int navigation_accept = 2130837598; + public const int ic_storage_gdrive = 2130837598; // aapt resource value: 0x7f02005f - public const int navigation_accept_dark = 2130837599; + public const int ic_storage_http = 2130837599; // aapt resource value: 0x7f020060 - public const int navigation_cancel = 2130837600; + public const int ic_storage_https = 2130837600; // aapt resource value: 0x7f020061 - public const int navigation_previous_item = 2130837601; + public const int ic_unlocked_gray = 2130837601; // aapt resource value: 0x7f020062 - public const int navigation_previous_item_dark = 2130837602; + public const int location_web_site = 2130837602; // aapt resource value: 0x7f020063 - public const int notify = 2130837603; + public const int navigation_accept = 2130837603; // aapt resource value: 0x7f020064 - public const int notify_keyboard = 2130837604; + public const int navigation_accept_dark = 2130837604; // aapt resource value: 0x7f020065 - public const int oktoberfest = 2130837605; + public const int navigation_cancel = 2130837605; // aapt resource value: 0x7f020066 - public const int RedButton = 2130837606; + public const int navigation_previous_item = 2130837606; // aapt resource value: 0x7f020067 - public const int section_header = 2130837607; + public const int navigation_previous_item_dark = 2130837607; // aapt resource value: 0x7f020068 - public const int sym_keyboard = 2130837608; + public const int notify = 2130837608; // aapt resource value: 0x7f020069 - public const int sym_keyboard_delete = 2130837609; + public const int notify_keyboard = 2130837609; // aapt resource value: 0x7f02006a - public const int sym_keyboard_done = 2130837610; + public const int oktoberfest = 2130837610; // aapt resource value: 0x7f02006b - public const int sym_keyboard_kp2a = 2130837611; + public const int RedButton = 2130837611; // aapt resource value: 0x7f02006c - public const int sym_keyboard_return = 2130837612; + public const int section_header = 2130837612; // aapt resource value: 0x7f02006d - public const int sym_keyboard_search = 2130837613; + public const int sym_keyboard = 2130837613; // aapt resource value: 0x7f02006e - public const int sym_keyboard_shift = 2130837614; + public const int sym_keyboard_delete = 2130837614; // aapt resource value: 0x7f02006f - public const int sym_keyboard_space = 2130837615; + public const int sym_keyboard_done = 2130837615; // aapt resource value: 0x7f020070 - public const int transparent = 2130837616; + public const int sym_keyboard_kp2a = 2130837616; // aapt resource value: 0x7f020071 - public const int YellowButton = 2130837617; + public const int sym_keyboard_return = 2130837617; + + // aapt resource value: 0x7f020072 + public const int sym_keyboard_search = 2130837618; + + // aapt resource value: 0x7f020073 + public const int sym_keyboard_shift = 2130837619; + + // aapt resource value: 0x7f020074 + public const int sym_keyboard_space = 2130837620; + + // aapt resource value: 0x7f020075 + public const int transparent = 2130837621; + + // aapt resource value: 0x7f020076 + public const int YellowButton = 2130837622; static Drawable() { @@ -593,44 +608,44 @@ namespace keepass2android // aapt resource value: 0x7f0d000f public const int Credit = 2131558415; - // aapt resource value: 0x7f0d007d - public const int IconGridView = 2131558525; + // aapt resource value: 0x7f0d0080 + public const int IconGridView = 2131558528; - // aapt resource value: 0x7f0d008c - public const int QuickUnlock_button = 2131558540; + // aapt resource value: 0x7f0d008f + public const int QuickUnlock_button = 2131558543; + + // aapt resource value: 0x7f0d0090 + public const int QuickUnlock_buttonLock = 2131558544; // aapt resource value: 0x7f0d008d - public const int QuickUnlock_buttonLock = 2131558541; + public const int QuickUnlock_label = 2131558541; - // aapt resource value: 0x7f0d008a - public const int QuickUnlock_label = 2131558538; + // aapt resource value: 0x7f0d008e + public const int QuickUnlock_password = 2131558542; - // aapt resource value: 0x7f0d008b - public const int QuickUnlock_password = 2131558539; + // aapt resource value: 0x7f0d0062 + public const int RelativeLayout = 2131558498; - // aapt resource value: 0x7f0d005f - public const int RelativeLayout = 2131558495; - - // aapt resource value: 0x7f0d005e - public const int ScrollView = 2131558494; + // aapt resource value: 0x7f0d0061 + public const int ScrollView = 2131558497; // aapt resource value: 0x7f0d0000 public const int about_title = 2131558400; - // aapt resource value: 0x7f0d005c - public const int accept_button = 2131558492; + // aapt resource value: 0x7f0d005f + public const int accept_button = 2131558495; // aapt resource value: 0x7f0d0031 public const int add_advanced = 2131558449; - // aapt resource value: 0x7f0d0072 - public const int add_entry = 2131558514; + // aapt resource value: 0x7f0d0075 + public const int add_entry = 2131558517; - // aapt resource value: 0x7f0d0071 - public const int add_group = 2131558513; + // aapt resource value: 0x7f0d0074 + public const int add_group = 2131558516; - // aapt resource value: 0x7f0d00a0 - public const int add_url_entry = 2131558560; + // aapt resource value: 0x7f0d00a3 + public const int add_url_entry = 2131558563; // aapt resource value: 0x7f0d0030 public const int advanced_container = 2131558448; @@ -650,83 +665,83 @@ namespace keepass2android // aapt resource value: 0x7f0d0055 public const int browse_button = 2131558485; - // aapt resource value: 0x7f0d0064 - public const int btn_length12 = 2131558500; - - // aapt resource value: 0x7f0d0063 - public const int btn_length16 = 2131558499; + // aapt resource value: 0x7f0d0067 + public const int btn_length12 = 2131558503; // aapt resource value: 0x7f0d0066 - public const int btn_length6 = 2131558502; + public const int btn_length16 = 2131558502; - // aapt resource value: 0x7f0d0065 - public const int btn_length8 = 2131558501; + // aapt resource value: 0x7f0d0069 + public const int btn_length6 = 2131558505; + + // aapt resource value: 0x7f0d0068 + public const int btn_length8 = 2131558504; // aapt resource value: 0x7f0d0013 public const int cancel = 2131558419; - // aapt resource value: 0x7f0d005d - public const int cancel_button = 2131558493; + // aapt resource value: 0x7f0d0060 + public const int cancel_button = 2131558496; - // aapt resource value: 0x7f0d0074 - public const int cancel_insert_element = 2131558516; + // aapt resource value: 0x7f0d0077 + public const int cancel_insert_element = 2131558519; - // aapt resource value: 0x7f0d009d - public const int cbCaseSensitive = 2131558557; + // aapt resource value: 0x7f0d00a0 + public const int cbCaseSensitive = 2131558560; - // aapt resource value: 0x7f0d009e - public const int cbExcludeExpiredEntries = 2131558558; - - // aapt resource value: 0x7f0d0093 - public const int cbRegEx = 2131558547; - - // aapt resource value: 0x7f0d009c - public const int cbSearchInGroupName = 2131558556; - - // aapt resource value: 0x7f0d0099 - public const int cbSearchInNotes = 2131558553; - - // aapt resource value: 0x7f0d009a - public const int cbSearchInOtherStrings = 2131558554; - - // aapt resource value: 0x7f0d0098 - public const int cbSearchInPassword = 2131558552; - - // aapt resource value: 0x7f0d009b - public const int cbSearchInTags = 2131558555; - - // aapt resource value: 0x7f0d0095 - public const int cbSearchInTitle = 2131558549; + // aapt resource value: 0x7f0d00a1 + public const int cbExcludeExpiredEntries = 2131558561; // aapt resource value: 0x7f0d0096 - public const int cbSearchInUrl = 2131558550; + public const int cbRegEx = 2131558550; - // aapt resource value: 0x7f0d0097 - public const int cbSearchInUsername = 2131558551; + // aapt resource value: 0x7f0d009f + public const int cbSearchInGroupName = 2131558559; - // aapt resource value: 0x7f0d006f - public const int cb_brackets = 2131558511; + // aapt resource value: 0x7f0d009c + public const int cbSearchInNotes = 2131558556; - // aapt resource value: 0x7f0d006a - public const int cb_digits = 2131558506; + // aapt resource value: 0x7f0d009d + public const int cbSearchInOtherStrings = 2131558557; - // aapt resource value: 0x7f0d0069 - public const int cb_lowercase = 2131558505; + // aapt resource value: 0x7f0d009b + public const int cbSearchInPassword = 2131558555; - // aapt resource value: 0x7f0d006b - public const int cb_minus = 2131558507; + // aapt resource value: 0x7f0d009e + public const int cbSearchInTags = 2131558558; + + // aapt resource value: 0x7f0d0098 + public const int cbSearchInTitle = 2131558552; + + // aapt resource value: 0x7f0d0099 + public const int cbSearchInUrl = 2131558553; + + // aapt resource value: 0x7f0d009a + public const int cbSearchInUsername = 2131558554; + + // aapt resource value: 0x7f0d0072 + public const int cb_brackets = 2131558514; // aapt resource value: 0x7f0d006d - public const int cb_space = 2131558509; - - // aapt resource value: 0x7f0d006e - public const int cb_specials = 2131558510; + public const int cb_digits = 2131558509; // aapt resource value: 0x7f0d006c - public const int cb_underline = 2131558508; + public const int cb_lowercase = 2131558508; - // aapt resource value: 0x7f0d0068 - public const int cb_uppercase = 2131558504; + // aapt resource value: 0x7f0d006e + public const int cb_minus = 2131558510; + + // aapt resource value: 0x7f0d0070 + public const int cb_space = 2131558512; + + // aapt resource value: 0x7f0d0071 + public const int cb_specials = 2131558513; + + // aapt resource value: 0x7f0d006f + public const int cb_underline = 2131558511; + + // aapt resource value: 0x7f0d006b + public const int cb_uppercase = 2131558507; // aapt resource value: 0x7f0d000b public const int contributors_title = 2131558411; @@ -734,14 +749,14 @@ namespace keepass2android // aapt resource value: 0x7f0d0058 public const int create = 2131558488; - // aapt resource value: 0x7f0d00a6 - public const int cred_password = 2131558566; + // aapt resource value: 0x7f0d00a9 + public const int cred_password = 2131558569; - // aapt resource value: 0x7f0d00a7 - public const int cred_remember_mode = 2131558567; + // aapt resource value: 0x7f0d00aa + public const int cred_remember_mode = 2131558570; - // aapt resource value: 0x7f0d00a5 - public const int cred_username = 2131558565; + // aapt resource value: 0x7f0d00a8 + public const int cred_username = 2131558568; // aapt resource value: 0x7f0d001d public const int delete_extra = 2131558429; @@ -767,8 +782,8 @@ namespace keepass2android // aapt resource value: 0x7f0d003b public const int edit_extra = 2131558459; - // aapt resource value: 0x7f0d0086 - public const int enable_quickunlock = 2131558534; + // aapt resource value: 0x7f0d0089 + public const int enable_quickunlock = 2131558537; // aapt resource value: 0x7f0d004c public const int entry_accessed = 2131558476; @@ -899,17 +914,23 @@ namespace keepass2android // aapt resource value: 0x7f0d005b public const int file_select = 2131558491; - // aapt resource value: 0x7f0d0081 - public const int filename = 2131558529; + // aapt resource value: 0x7f0d0084 + public const int filename = 2131558532; // aapt resource value: 0x7f0d0053 public const int filename_form = 2131558483; - // aapt resource value: 0x7f0d007f - public const int filename_label = 2131558527; + // aapt resource value: 0x7f0d0082 + public const int filename_label = 2131558530; - // aapt resource value: 0x7f0d0080 - public const int filenamescroll = 2131558528; + // aapt resource value: 0x7f0d0083 + public const int filenamescroll = 2131558531; + + // aapt resource value: 0x7f0d005e + public const int filestorage_label = 2131558494; + + // aapt resource value: 0x7f0d005d + public const int filestorage_logo = 2131558493; // aapt resource value: 0x7f0d0059 public const int fnv_cancel = 2131558489; @@ -920,41 +941,41 @@ namespace keepass2android // aapt resource value: 0x7f0d0029 public const int generate_button = 2131558441; - // aapt resource value: 0x7f0d0061 - public const int generate_password_button = 2131558497; + // aapt resource value: 0x7f0d0064 + public const int generate_password_button = 2131558500; - // aapt resource value: 0x7f0d0070 - public const int group_header = 2131558512; + // aapt resource value: 0x7f0d0073 + public const int group_header = 2131558515; + + // aapt resource value: 0x7f0d007b + public const int group_icon = 2131558523; + + // aapt resource value: 0x7f0d007d + public const int group_label = 2131558525; // aapt resource value: 0x7f0d0078 - public const int group_icon = 2131558520; + public const int group_name = 2131558520; + + // aapt resource value: 0x7f0d007c + public const int group_text = 2131558524; // aapt resource value: 0x7f0d007a - public const int group_label = 2131558522; - - // aapt resource value: 0x7f0d0075 - public const int group_name = 2131558517; - - // aapt resource value: 0x7f0d0079 - public const int group_text = 2131558521; - - // aapt resource value: 0x7f0d0077 - public const int icon = 2131558519; + public const int icon = 2131558522; // aapt resource value: 0x7f0d0022 public const int icon_button = 2131558434; - // aapt resource value: 0x7f0d007b - public const int icon_image = 2131558523; + // aapt resource value: 0x7f0d007e + public const int icon_image = 2131558526; - // aapt resource value: 0x7f0d007c - public const int icon_text = 2131558524; + // aapt resource value: 0x7f0d007f + public const int icon_text = 2131558527; // aapt resource value: 0x7f0d0017 public const int imgoktfest = 2131558423; - // aapt resource value: 0x7f0d0073 - public const int insert_element = 2131558515; + // aapt resource value: 0x7f0d0076 + public const int insert_element = 2131558518; // aapt resource value: 0x7f0d0011 public const int install_market = 2131558417; @@ -962,11 +983,11 @@ namespace keepass2android // aapt resource value: 0x7f0d0012 public const int install_web = 2131558418; - // aapt resource value: 0x7f0d007e - public const int keyboard = 2131558526; + // aapt resource value: 0x7f0d0081 + public const int keyboard = 2131558529; - // aapt resource value: 0x7f0d0088 - public const int keyfileLine = 2131558536; + // aapt resource value: 0x7f0d008b + public const int keyfileLine = 2131558539; // aapt resource value: 0x7f0d0054 public const int label_open_by_filename = 2131558484; @@ -977,71 +998,71 @@ namespace keepass2android // aapt resource value: 0x7f0d004f public const int label_warning = 2131558479; - // aapt resource value: 0x7f0d0067 - public const int length = 2131558503; + // aapt resource value: 0x7f0d006a + public const int length = 2131558506; - // aapt resource value: 0x7f0d0062 - public const int length_label = 2131558498; + // aapt resource value: 0x7f0d0065 + public const int length_label = 2131558501; - // aapt resource value: 0x7f0d0092 - public const int linearLayout1 = 2131558546; - - // aapt resource value: 0x7f0d00b1 - public const int menu_about = 2131558577; - - // aapt resource value: 0x7f0d00b0 - public const int menu_app_settings = 2131558576; - - // aapt resource value: 0x7f0d00af - public const int menu_cancel_edit = 2131558575; - - // aapt resource value: 0x7f0d00b7 - public const int menu_change_db = 2131558583; - - // aapt resource value: 0x7f0d00b3 - public const int menu_change_master_key = 2131558579; - - // aapt resource value: 0x7f0d00a8 - public const int menu_donate = 2131558568; - - // aapt resource value: 0x7f0d00aa - public const int menu_goto_url = 2131558570; - - // aapt resource value: 0x7f0d00ab - public const int menu_lock = 2131558571; - - // aapt resource value: 0x7f0d00ad - public const int menu_rate = 2131558573; - - // aapt resource value: 0x7f0d00b2 - public const int menu_search = 2131558578; - - // aapt resource value: 0x7f0d00b6 - public const int menu_search_advanced = 2131558582; - - // aapt resource value: 0x7f0d00b5 - public const int menu_sort = 2131558581; - - // aapt resource value: 0x7f0d00ac - public const int menu_suggest_improvements = 2131558572; + // aapt resource value: 0x7f0d0095 + public const int linearLayout1 = 2131558549; // aapt resource value: 0x7f0d00b4 - public const int menu_sync = 2131558580; + public const int menu_about = 2131558580; - // aapt resource value: 0x7f0d00a9 - public const int menu_toggle_pass = 2131558569; + // aapt resource value: 0x7f0d00b3 + public const int menu_app_settings = 2131558579; + + // aapt resource value: 0x7f0d00b2 + public const int menu_cancel_edit = 2131558578; + + // aapt resource value: 0x7f0d00ba + public const int menu_change_db = 2131558586; + + // aapt resource value: 0x7f0d00b6 + public const int menu_change_master_key = 2131558582; + + // aapt resource value: 0x7f0d00ab + public const int menu_donate = 2131558571; + + // aapt resource value: 0x7f0d00ad + public const int menu_goto_url = 2131558573; // aapt resource value: 0x7f0d00ae - public const int menu_translate = 2131558574; + public const int menu_lock = 2131558574; + + // aapt resource value: 0x7f0d00b0 + public const int menu_rate = 2131558576; + + // aapt resource value: 0x7f0d00b5 + public const int menu_search = 2131558581; + + // aapt resource value: 0x7f0d00b9 + public const int menu_search_advanced = 2131558585; + + // aapt resource value: 0x7f0d00b8 + public const int menu_sort = 2131558584; + + // aapt resource value: 0x7f0d00af + public const int menu_suggest_improvements = 2131558575; + + // aapt resource value: 0x7f0d00b7 + public const int menu_sync = 2131558583; + + // aapt resource value: 0x7f0d00ac + public const int menu_toggle_pass = 2131558572; + + // aapt resource value: 0x7f0d00b1 + public const int menu_translate = 2131558577; // aapt resource value: 0x7f0d0019 public const int no_donate = 2131558425; - // aapt resource value: 0x7f0d00a1 - public const int no_results = 2131558561; + // aapt resource value: 0x7f0d00a4 + public const int no_results = 2131558564; - // aapt resource value: 0x7f0d0076 - public const int ok = 2131558518; + // aapt resource value: 0x7f0d0079 + public const int ok = 2131558521; // aapt resource value: 0x7f0d0018 public const int ok_donate = 2131558424; @@ -1049,26 +1070,26 @@ namespace keepass2android // aapt resource value: 0x7f0d0057 public const int open = 2131558487; - // aapt resource value: 0x7f0d00a3 - public const int pass_conf_password = 2131558563; - - // aapt resource value: 0x7f0d0084 - public const int pass_keyfile = 2131558532; - - // aapt resource value: 0x7f0d0085 - public const int pass_ok = 2131558533; - - // aapt resource value: 0x7f0d00a2 - public const int pass_password = 2131558562; - - // aapt resource value: 0x7f0d0060 - public const int password = 2131558496; + // aapt resource value: 0x7f0d00a6 + public const int pass_conf_password = 2131558566; // aapt resource value: 0x7f0d0087 - public const int passwordLine = 2131558535; + public const int pass_keyfile = 2131558535; - // aapt resource value: 0x7f0d0082 - public const int password_label = 2131558530; + // aapt resource value: 0x7f0d0088 + public const int pass_ok = 2131558536; + + // aapt resource value: 0x7f0d00a5 + public const int pass_password = 2131558565; + + // aapt resource value: 0x7f0d0063 + public const int password = 2131558499; + + // aapt resource value: 0x7f0d008a + public const int passwordLine = 2131558538; + + // aapt resource value: 0x7f0d0085 + public const int password_label = 2131558533; // aapt resource value: 0x7f0d000e public const int plugin1 = 2131558414; @@ -1076,8 +1097,8 @@ namespace keepass2android // aapt resource value: 0x7f0d001c public const int protection = 2131558428; - // aapt resource value: 0x7f0d0089 - public const int qu_filename = 2131558537; + // aapt resource value: 0x7f0d008c + public const int qu_filename = 2131558540; // aapt resource value: 0x7f0d0014 public const int rounds = 2131558420; @@ -1085,29 +1106,29 @@ namespace keepass2android // aapt resource value: 0x7f0d0015 public const int rounds_explaination = 2131558421; - // aapt resource value: 0x7f0d0091 - public const int scrollView1 = 2131558545; - - // aapt resource value: 0x7f0d0090 - public const int searchEditText = 2131558544; - - // aapt resource value: 0x7f0d008f - public const int search_button = 2131558543; - // aapt resource value: 0x7f0d0094 - public const int search_in_label = 2131558548; + public const int scrollView1 = 2131558548; - // aapt resource value: 0x7f0d008e - public const int search_label = 2131558542; + // aapt resource value: 0x7f0d0093 + public const int searchEditText = 2131558547; - // aapt resource value: 0x7f0d009f - public const int select_other_entry = 2131558559; + // aapt resource value: 0x7f0d0092 + public const int search_button = 2131558546; + + // aapt resource value: 0x7f0d0097 + public const int search_in_label = 2131558551; + + // aapt resource value: 0x7f0d0091 + public const int search_label = 2131558545; + + // aapt resource value: 0x7f0d00a2 + public const int select_other_entry = 2131558562; // aapt resource value: 0x7f0d0052 public const int start_create = 2131558482; - // aapt resource value: 0x7f0d00a4 - public const int start_create_import = 2131558564; + // aapt resource value: 0x7f0d00a7 + public const int start_create_import = 2131558567; // aapt resource value: 0x7f0d0050 public const int start_open_file = 2131558480; @@ -1118,14 +1139,17 @@ namespace keepass2android // aapt resource value: 0x7f0d0010 public const int text = 2131558416; + // aapt resource value: 0x7f0d005c + public const int textView = 2131558492; + // aapt resource value: 0x7f0d001a public const int title = 2131558426; // aapt resource value: 0x7f0d003f public const int title_block = 2131558463; - // aapt resource value: 0x7f0d0083 - public const int toggle_password = 2131558531; + // aapt resource value: 0x7f0d0086 + public const int toggle_password = 2131558534; // aapt resource value: 0x7f0d0044 public const int top = 2131558468; @@ -1213,64 +1237,70 @@ namespace keepass2android public const int file_selection_no_recent = 2130903058; // aapt resource value: 0x7f030013 - public const int generate_password = 2130903059; + public const int filestorage_selection = 2130903059; // aapt resource value: 0x7f030014 - public const int group_add_entry = 2130903060; + public const int filestorage_selection_listitem = 2130903060; // aapt resource value: 0x7f030015 - public const int group_edit = 2130903061; + public const int generate_password = 2130903061; // aapt resource value: 0x7f030016 - public const int group_empty = 2130903062; + public const int group_add_entry = 2130903062; // aapt resource value: 0x7f030017 - public const int group_header = 2130903063; + public const int group_edit = 2130903063; // aapt resource value: 0x7f030018 - public const int group_list_entry = 2130903064; + public const int group_empty = 2130903064; // aapt resource value: 0x7f030019 - public const int icon = 2130903065; + public const int group_header = 2130903065; // aapt resource value: 0x7f03001a - public const int icon_picker = 2130903066; + public const int group_list_entry = 2130903066; // aapt resource value: 0x7f03001b - public const int input = 2130903067; + public const int icon = 2130903067; // aapt resource value: 0x7f03001c - public const int InViewButton = 2130903068; + public const int icon_picker = 2130903068; // aapt resource value: 0x7f03001d - public const int password = 2130903069; + public const int input = 2130903069; // aapt resource value: 0x7f03001e - public const int QuickUnlock = 2130903070; + public const int InViewButton = 2130903070; // aapt resource value: 0x7f03001f - public const int QuickUnlock_Unused = 2130903071; + public const int password = 2130903071; // aapt resource value: 0x7f030020 - public const int SaveButton = 2130903072; + public const int QuickUnlock = 2130903072; // aapt resource value: 0x7f030021 - public const int search = 2130903073; + public const int QuickUnlock_Unused = 2130903073; // aapt resource value: 0x7f030022 - public const int searchurlresults = 2130903074; + public const int SaveButton = 2130903074; // aapt resource value: 0x7f030023 - public const int searchurlresults_empty = 2130903075; + public const int search = 2130903075; // aapt resource value: 0x7f030024 - public const int set_password = 2130903076; + public const int searchurlresults = 2130903076; // aapt resource value: 0x7f030025 - public const int StartScreenButtons = 2130903077; + public const int searchurlresults_empty = 2130903077; // aapt resource value: 0x7f030026 - public const int url_credentials = 2130903078; + public const int set_password = 2130903078; + + // aapt resource value: 0x7f030027 + public const int StartScreenButtons = 2130903079; + + // aapt resource value: 0x7f030028 + public const int url_credentials = 2130903080; static Layout() { @@ -1376,38 +1406,38 @@ namespace keepass2android // aapt resource value: 0x7f060166 public const int CannotMoveGroupHere = 2131100006; + // aapt resource value: 0x7f06017a + public const int ChangeLog = 2131100026; + + // aapt resource value: 0x7f060179 + public const int ChangeLog_0_7 = 2131100025; + + // aapt resource value: 0x7f060177 + public const int ChangeLog_0_8 = 2131100023; + + // aapt resource value: 0x7f060176 + public const int ChangeLog_0_8_1 = 2131100022; + + // aapt resource value: 0x7f060175 + public const int ChangeLog_0_8_2 = 2131100021; + // aapt resource value: 0x7f060174 - public const int ChangeLog = 2131100020; + public const int ChangeLog_0_8_3 = 2131100020; // aapt resource value: 0x7f060173 - public const int ChangeLog_0_7 = 2131100019; - - // aapt resource value: 0x7f060171 - public const int ChangeLog_0_8 = 2131100017; - - // aapt resource value: 0x7f060170 - public const int ChangeLog_0_8_1 = 2131100016; - - // aapt resource value: 0x7f06016f - public const int ChangeLog_0_8_2 = 2131100015; - - // aapt resource value: 0x7f06016e - public const int ChangeLog_0_8_3 = 2131100014; - - // aapt resource value: 0x7f06016d - public const int ChangeLog_0_8_4 = 2131100013; - - // aapt resource value: 0x7f06016c - public const int ChangeLog_0_8_5 = 2131100012; - - // aapt resource value: 0x7f06016b - public const int ChangeLog_0_8_6 = 2131100011; + public const int ChangeLog_0_8_4 = 2131100019; // aapt resource value: 0x7f060172 - public const int ChangeLog_keptDonate = 2131100018; + public const int ChangeLog_0_8_5 = 2131100018; - // aapt resource value: 0x7f06016a - public const int ChangeLog_title = 2131100010; + // aapt resource value: 0x7f060171 + public const int ChangeLog_0_8_6 = 2131100017; + + // aapt resource value: 0x7f060178 + public const int ChangeLog_keptDonate = 2131100024; + + // aapt resource value: 0x7f060170 + public const int ChangeLog_title = 2131100016; // aapt resource value: 0x7f060032 public const int CheckForFileChangesOnSave_key = 2131099698; @@ -2024,6 +2054,24 @@ namespace keepass2android // aapt resource value: 0x7f060094 public const int file_browser = 2131099796; + // aapt resource value: 0x7f06016e + public const int filestoragename_dropbox = 2131100014; + + // aapt resource value: 0x7f06016a + public const int filestoragename_file = 2131100010; + + // aapt resource value: 0x7f06016b + public const int filestoragename_ftp = 2131100011; + + // aapt resource value: 0x7f06016f + public const int filestoragename_gdrive = 2131100015; + + // aapt resource value: 0x7f06016c + public const int filestoragename_http = 2131100012; + + // aapt resource value: 0x7f06016d + public const int filestoragename_https = 2131100013; + // aapt resource value: 0x7f06000f public const int further_author_names = 2131099663; @@ -2445,14 +2493,14 @@ namespace keepass2android public partial class Style { - // aapt resource value: 0x7f0b001b - public const int AdditionalStringLayout = 2131427355; + // aapt resource value: 0x7f0b001d + public const int AdditionalStringLayout = 2131427357; // aapt resource value: 0x7f0b0000 public const int Base = 2131427328; - // aapt resource value: 0x7f0b0015 - public const int BottomBarActionButton = 2131427349; + // aapt resource value: 0x7f0b0017 + public const int BottomBarActionButton = 2131427351; // aapt resource value: 0x7f0b0002 public const int Dialog = 2131427330; @@ -2505,20 +2553,26 @@ namespace keepass2android // aapt resource value: 0x7f0b0001 public const int NoTitleBar = 2131427329; - // aapt resource value: 0x7f0b0018 - public const int TextAppearance_EditEntry = 2131427352; - - // aapt resource value: 0x7f0b0017 - public const int TextAppearance_EditEntry_LabelSmall = 2131427351; + // aapt resource value: 0x7f0b0015 + public const int PaddedContainer = 2131427349; // aapt resource value: 0x7f0b0016 - public const int TextAppearance_EditEntry_Small = 2131427350; - - // aapt resource value: 0x7f0b0019 - public const int TextAppearance_EditEntry_Value = 2131427353; + public const int PaddedElement = 2131427350; // aapt resource value: 0x7f0b001a - public const int TextAppearance_SmallHeading = 2131427354; + public const int TextAppearance_EditEntry = 2131427354; + + // aapt resource value: 0x7f0b0019 + public const int TextAppearance_EditEntry_LabelSmall = 2131427353; + + // aapt resource value: 0x7f0b0018 + public const int TextAppearance_EditEntry_Small = 2131427352; + + // aapt resource value: 0x7f0b001b + public const int TextAppearance_EditEntry_Value = 2131427355; + + // aapt resource value: 0x7f0b001c + public const int TextAppearance_SmallHeading = 2131427356; // aapt resource value: 0x7f0b000a public const int WhiteOnBlack = 2131427338; diff --git a/src/keepass2android/Resources/drawable-hdpi/ic_storage_dropbox.png b/src/keepass2android/Resources/drawable-hdpi/ic_storage_dropbox.png new file mode 100644 index 00000000..3170535d Binary files /dev/null and b/src/keepass2android/Resources/drawable-hdpi/ic_storage_dropbox.png differ diff --git a/src/keepass2android/Resources/drawable-hdpi/ic_storage_ftp.png b/src/keepass2android/Resources/drawable-hdpi/ic_storage_ftp.png new file mode 100644 index 00000000..b5f28c47 Binary files /dev/null and b/src/keepass2android/Resources/drawable-hdpi/ic_storage_ftp.png differ diff --git a/src/keepass2android/Resources/drawable-hdpi/ic_storage_gdrive.png b/src/keepass2android/Resources/drawable-hdpi/ic_storage_gdrive.png new file mode 100644 index 00000000..d983a004 Binary files /dev/null and b/src/keepass2android/Resources/drawable-hdpi/ic_storage_gdrive.png differ diff --git a/src/keepass2android/Resources/drawable-hdpi/ic_storage_http.png b/src/keepass2android/Resources/drawable-hdpi/ic_storage_http.png new file mode 100644 index 00000000..b5f28c47 Binary files /dev/null and b/src/keepass2android/Resources/drawable-hdpi/ic_storage_http.png differ diff --git a/src/keepass2android/Resources/drawable-hdpi/ic_storage_https.png b/src/keepass2android/Resources/drawable-hdpi/ic_storage_https.png new file mode 100644 index 00000000..b5f28c47 Binary files /dev/null and b/src/keepass2android/Resources/drawable-hdpi/ic_storage_https.png differ diff --git a/src/keepass2android/Resources/drawable/ic_storage_dropbox.png b/src/keepass2android/Resources/drawable/ic_storage_dropbox.png new file mode 100644 index 00000000..27b8fc40 Binary files /dev/null and b/src/keepass2android/Resources/drawable/ic_storage_dropbox.png differ diff --git a/src/keepass2android/Resources/drawable/ic_storage_ftp.png b/src/keepass2android/Resources/drawable/ic_storage_ftp.png new file mode 100644 index 00000000..e164a9f3 Binary files /dev/null and b/src/keepass2android/Resources/drawable/ic_storage_ftp.png differ diff --git a/src/keepass2android/Resources/drawable/ic_storage_gdrive.png b/src/keepass2android/Resources/drawable/ic_storage_gdrive.png new file mode 100644 index 00000000..1761d023 Binary files /dev/null and b/src/keepass2android/Resources/drawable/ic_storage_gdrive.png differ diff --git a/src/keepass2android/Resources/drawable/ic_storage_http.png b/src/keepass2android/Resources/drawable/ic_storage_http.png new file mode 100644 index 00000000..e164a9f3 Binary files /dev/null and b/src/keepass2android/Resources/drawable/ic_storage_http.png differ diff --git a/src/keepass2android/Resources/drawable/ic_storage_https.png b/src/keepass2android/Resources/drawable/ic_storage_https.png new file mode 100644 index 00000000..e164a9f3 Binary files /dev/null and b/src/keepass2android/Resources/drawable/ic_storage_https.png differ diff --git a/src/keepass2android/Resources/layout/filestorage_selection.xml b/src/keepass2android/Resources/layout/filestorage_selection.xml new file mode 100644 index 00000000..1fdf3438 --- /dev/null +++ b/src/keepass2android/Resources/layout/filestorage_selection.xml @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/keepass2android/Resources/layout/filestorage_selection_listitem.xml b/src/keepass2android/Resources/layout/filestorage_selection_listitem.xml new file mode 100644 index 00000000..ae77705b --- /dev/null +++ b/src/keepass2android/Resources/layout/filestorage_selection_listitem.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/keepass2android/Resources/values/strings.xml b/src/keepass2android/Resources/values/strings.xml index 586c86d3..80a46cd8 100644 --- a/src/keepass2android/Resources/values/strings.xml +++ b/src/keepass2android/Resources/values/strings.xml @@ -314,6 +314,13 @@ Today, it\'s Oktoberfest! If you like Keepass2Android: wouldn\'t today be a good day to buy me a beer? Tell me more! No, I don\'t like it that much + + Local file + FTP + HTTP (WebDav) + HTTPS (WebDav) + Dropbox + Google Drive Change log diff --git a/src/keepass2android/Resources/values/styles.xml b/src/keepass2android/Resources/values/styles.xml index 42ee4bd2..1492a654 100644 --- a/src/keepass2android/Resources/values/styles.xml +++ b/src/keepass2android/Resources/values/styles.xml @@ -114,4 +114,17 @@ bold @android:color/transparent + + + + + \ No newline at end of file diff --git a/src/keepass2android/app/App.cs b/src/keepass2android/app/App.cs index dd7bf28f..0d17f293 100644 --- a/src/keepass2android/app/App.cs +++ b/src/keepass2android/app/App.cs @@ -20,6 +20,7 @@ using System.Collections.Generic; using System.IO; using Android.App; using Android.Content; +using Android.Graphics.Drawables; using Android.OS; using Android.Runtime; using Android.Widget; @@ -162,8 +163,9 @@ namespace keepass2android internal EntryEditActivityState EntryEditActivityState = null; public FileDbHelper FileDbHelper; + private List _fileStorages; - public Database GetDb() + public Database GetDb() { if (_db == null) { @@ -242,11 +244,22 @@ namespace keepass2android public string GetResourceString(UiStringKey key) { - var field = typeof (Resource.String).GetField(key.ToString()); - if (field == null) - throw new Exception("Invalid key " + key); - return Application.Context.GetString((int)field.GetValue(null)); + return GetResourceString(key.ToString()); } + public string GetResourceString(string key) + { + var field = typeof(Resource.String).GetField(key); + if (field == null) + throw new Exception("Invalid key " + key); + return Application.Context.GetString((int)field.GetValue(null)); + } + public Drawable GetResourceDrawable(string key) + { + var field = typeof(Resource.Drawable).GetField(key); + if (field == null) + throw new Exception("Invalid key " + key); + return Application.Context.Resources.GetDrawable((int)field.GetValue(null)); + } public void AskYesNoCancel(UiStringKey titleKey, UiStringKey messageKey, EventHandler yesHandler, @@ -335,18 +348,52 @@ namespace keepass2android return new BuiltInFileStorage(); else { + IFileStorage innerFileStorage = GetCloudFileStorage(iocInfo); + var prefs = PreferenceManager.GetDefaultSharedPreferences(Application.Context); + if (prefs.GetBoolean(Application.Context.Resources.GetString(Resource.String.UseOfflineCache_key), true)) { - return new CachingFileStorage(new BuiltInFileStorage(), Application.Context.CacheDir.Path, this); + return new CachingFileStorage(innerFileStorage, Application.Context.CacheDir.Path, this); } else { - return new BuiltInFileStorage(); + return innerFileStorage; } } } + private IFileStorage GetCloudFileStorage(IOConnectionInfo iocInfo) + { + foreach (IFileStorage fs in FileStorages) + { + foreach (string protocolId in fs.SupportedProtocols) + { + if (iocInfo.Path.StartsWith(protocolId + "://")) + return fs; + } + + } + //TODO: catch! + throw new Exception("Unknown protocol " + iocInfo); + } + + public IEnumerable FileStorages + { + get + { + if (_fileStorages == null) + { + _fileStorages = new List + { + new DropboxFileStorage(Application.Context), + new BuiltInFileStorage() + }; + } + return _fileStorages; + } + } + public void TriggerReload(Context ctx) { Handler handler = new Handler(Looper.MainLooper); @@ -432,6 +479,11 @@ namespace keepass2android { new CachingFileStorage(new BuiltInFileStorage(), Application.Context.CacheDir.Path, this).ClearCache(); } + + public IFileStorage GetFileStorage(string protocolId) + { + return GetFileStorage(new IOConnectionInfo() {Path = protocolId + "://"}); + } } diff --git a/src/keepass2android/fileselect/FileSelectActivity.cs b/src/keepass2android/fileselect/FileSelectActivity.cs index ec9d7d7c..2e410795 100644 --- a/src/keepass2android/fileselect/FileSelectActivity.cs +++ b/src/keepass2android/fileselect/FileSelectActivity.cs @@ -224,6 +224,7 @@ namespace keepass2android + Button openFileButton = (Button)FindViewById(Resource.Id.start_open_file); @@ -243,8 +244,12 @@ namespace keepass2android openUrlButton.Visibility = ViewStates.Gone; #endif - EventHandler openUrlButtonClick = (sender, e) => ShowFilenameDialog(true, false, false, "", GetString(Resource.String.enter_filename_details_url), Intents.RequestCodeFileBrowseForOpen); - openUrlButton.Click += openUrlButtonClick; + //EventHandler openUrlButtonClick = (sender, e) => ShowFilenameDialog(true, false, false, "", GetString(Resource.String.enter_filename_details_url), Intents.RequestCodeFileBrowseForOpen); + openUrlButton.Click += (sender, args) => + { + Intent intent = new Intent(this, typeof(FileStorageSelectionActivity)); + StartActivityForResult(intent, 0); + }; //CREATE NEW Button createNewButton = (Button)FindViewById(Resource.Id.start_create); @@ -377,7 +382,7 @@ namespace keepass2android void LaunchPasswordActivityForIoc(IOConnectionInfo ioc) { - if ((!ioc.IsLocalFile()) && (ioc.CredSaveMode != IOCredSaveMode.SaveCred)) + if (App.Kp2a.GetFileStorage(ioc).RequiresCredentials(ioc)) { //Build dialog to query credentials: AlertDialog.Builder builder = new AlertDialog.Builder(this); @@ -443,6 +448,15 @@ namespace keepass2android } FillData(); + + if (resultCode == KeePass.ExitFileStorageSelectionOk) + { + LaunchPasswordActivityForIoc(new IOConnectionInfo() + { + Path = data.GetStringExtra("protocolId")+":///keepass/keepass.kdbx" + } + ); + } if ( (requestCode == Intents.RequestCodeFileBrowseForCreate || requestCode == Intents.RequestCodeFileBrowseForOpen) diff --git a/src/keepass2android/keepass2android.csproj b/src/keepass2android/keepass2android.csproj index e49addbe..ed78c11d 100644 --- a/src/keepass2android/keepass2android.csproj +++ b/src/keepass2android/keepass2android.csproj @@ -78,6 +78,7 @@ + @@ -654,6 +655,10 @@ + + {48574278-4779-4b3a-a9e4-9cf1bc285d0b} + JavaFileStorageBindings + {545B4A6B-8BBA-4FBE-92FC-4AC060122A54} KeePassLib2Android @@ -765,4 +770,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file