* Added file chooser to KP2A

* added functionality to file storage interface and (some) implementations to delete files/folders, create folders, list contents
-> Dropbox functionality implemented
This commit is contained in:
Philipp Crocoll 2013-09-28 07:46:44 +02:00
parent 15b7ca38c8
commit 74acd19092
40 changed files with 5346 additions and 1694 deletions

View File

@ -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; }
}

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{3C0F7FE5-639F-4422-A087-8B26CF862D1B}</ProjectGuid>
<ProjectTypeGuids>{10368E6C-D01B-4462-8E8B-01FC667A7035};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>AndroidFileChooserBinding</RootNamespace>
<AssemblyName>AndroidFileChooserBinding</AssemblyName>
<FileAlignment>512</FileAlignment>
<TargetFrameworkVersion>v2.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<LibraryProjectZip Include="..\java\android-filechooser\code\project.zip">
<Link>project.zip</Link>
</LibraryProjectZip>
<None Include="Jars\AboutJars.txt" />
<None Include="Additions\AboutAdditions.txt" />
</ItemGroup>
<ItemGroup>
<TransformFile Include="Transforms\Metadata.xml" />
<TransformFile Include="Transforms\EnumFields.xml" />
<TransformFile Include="Transforms\EnumMethods.xml" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\android-support-v4.jar" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -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".

View File

@ -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("AndroidFileChooserBinding")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AndroidFileChooserBinding")]
[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)]

View File

@ -0,0 +1,14 @@
<enum-field-mappings>
<!--
This example converts the constants Fragment_id, Fragment_name,
and Fragment_tag from android.support.v4.app.FragmentActivity.FragmentTag
to an enum called Android.Support.V4.App.FragmentTagType with values
Id, Name, and Tag.
<mapping jni-class="android/support/v4/app/FragmentActivity$FragmentTag" clr-enum-type="Android.Support.V4.App.FragmentTagType">
<field jni-name="Fragment_name" clr-name="Name" value="0" />
<field jni-name="Fragment_id" clr-name="Id" value="1" />
<field jni-name="Fragment_tag" clr-name="Tag" value="2" />
</mapping>
-->
</enum-field-mappings>

View File

@ -0,0 +1,13 @@
<enum-method-mappings>
<!--
This example changes the Java method:
android.support.v4.app.Fragment.SavedState.writeToParcel (int flags)
to be:
android.support.v4.app.Fragment.SavedState.writeToParcel (Android.OS.ParcelableWriteFlags flags)
when bound in C#.
<mapping jni-class="android/support/v4/app/Fragment.SavedState">
<method jni-name="writeToParcel" parameter="flags" clr-enum-type="Android.OS.ParcelableWriteFlags" />
</mapping>
-->
</enum-method-mappings>

View File

@ -0,0 +1,19 @@
<metadata>
<remove-node path="/api/package[@name='group.pals.android.lib.ui.filechooser.providers.localfile']/class[@name='FileObserverEx']" />
<!--
<remove-node path="/api/package[@name='group.pals.android.lib.ui.filechooser']/class[@name='FragmentFiles']" />
<remove-node path="/api/package[@name='group.pals.android.lib.ui.filechooser.utils.ui.bookmark']/class[@name='BookmarkFragment']" />
<remove-node path="/api/package[@name='group.pals.android.lib.ui.filechooser.utils.ui.history']/class[@name='HistoryFragment']" />
<remove-node path="/api/package[@name='group.pals.android.lib.ui.filechooser.prefs']/class[@name='DisplayPrefs']" />
This sample removes the class: android.support.v4.content.AsyncTaskLoader.LoadTask:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='AsyncTaskLoader.LoadTask']" />
This sample removes the method: android.support.v4.content.CursorLoader.loadInBackground:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='CursorLoader']/method[@name='loadInBackground']" />
-->
</metadata>

View File

@ -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; }
}

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{23233A28-D74F-4BF8-B4D8-834060840BD7}</ProjectGuid>
<ProjectTypeGuids>{10368E6C-D01B-4462-8E8B-01FC667A7035};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>AppCompatV7Binding</RootNamespace>
<AssemblyName>AppCompatV7Binding</AssemblyName>
<FileAlignment>512</FileAlignment>
<TargetFrameworkVersion>v2.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Jars\AboutJars.txt" />
<None Include="Additions\AboutAdditions.txt" />
<LibraryProjectZip Include="project_appcompatv7.zip" />
</ItemGroup>
<ItemGroup>
<TransformFile Include="Transforms\Metadata.xml" />
<TransformFile Include="Transforms\EnumFields.xml" />
<TransformFile Include="Transforms\EnumMethods.xml" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -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".

View File

@ -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("AppCompatV7Binding")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AppCompatV7Binding")]
[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)]

View File

@ -0,0 +1,14 @@
<enum-field-mappings>
<!--
This example converts the constants Fragment_id, Fragment_name,
and Fragment_tag from android.support.v4.app.FragmentActivity.FragmentTag
to an enum called Android.Support.V4.App.FragmentTagType with values
Id, Name, and Tag.
<mapping jni-class="android/support/v4/app/FragmentActivity$FragmentTag" clr-enum-type="Android.Support.V4.App.FragmentTagType">
<field jni-name="Fragment_name" clr-name="Name" value="0" />
<field jni-name="Fragment_id" clr-name="Id" value="1" />
<field jni-name="Fragment_tag" clr-name="Tag" value="2" />
</mapping>
-->
</enum-field-mappings>

View File

@ -0,0 +1,13 @@
<enum-method-mappings>
<!--
This example changes the Java method:
android.support.v4.app.Fragment.SavedState.writeToParcel (int flags)
to be:
android.support.v4.app.Fragment.SavedState.writeToParcel (Android.OS.ParcelableWriteFlags flags)
when bound in C#.
<mapping jni-class="android/support/v4/app/Fragment.SavedState">
<method jni-name="writeToParcel" parameter="flags" clr-enum-type="Android.OS.ParcelableWriteFlags" />
</mapping>
-->
</enum-method-mappings>

View File

@ -0,0 +1,9 @@
<metadata>
<!--
This sample removes the class: android.support.v4.content.AsyncTaskLoader.LoadTask:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='AsyncTaskLoader.LoadTask']" />
This sample removes the method: android.support.v4.content.CursorLoader.loadInBackground:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='CursorLoader']/method[@name='loadInBackground']" />
-->
</metadata>

Binary file not shown.

View File

@ -19,6 +19,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TwofishCipher", "TwofishCip
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JavaFileStorageBindings", "JavaFileStorageBindings\JavaFileStorageBindings.csproj", "{48574278-4779-4B3A-A9E4-9CF1BC285D0B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppCompatV7Binding", "AppCompatV7Binding\AppCompatV7Binding.csproj", "{23233A28-D74F-4BF8-B4D8-834060840BD7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AndroidFileChooserBinding", "AndroidFileChooserBinding\AndroidFileChooserBinding.csproj", "{3C0F7FE5-639F-4422-A087-8B26CF862D1B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -222,6 +226,42 @@ Global
{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
{23233A28-D74F-4BF8-B4D8-834060840BD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.Debug|Win32.ActiveCfg = Debug|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.Debug|x64.ActiveCfg = Debug|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.Release|Any CPU.Build.0 = Release|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.Release|Win32.ActiveCfg = Release|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.Release|x64.ActiveCfg = Release|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
{23233A28-D74F-4BF8-B4D8-834060840BD7}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Win32.ActiveCfg = Debug|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|x64.ActiveCfg = Debug|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Any CPU.Build.0 = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Win32.ActiveCfg = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|x64.ActiveCfg = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -30,11 +30,11 @@ namespace keepass2android.Io
}
}
public void DeleteFile(IOConnectionInfo ioc)
public void Delete(IOConnectionInfo ioc)
{
//todo check if directory
IOConnection.DeleteFile(ioc);
}
public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion)
{
if (!ioc.IsLocalFile())
@ -137,5 +137,17 @@ namespace keepass2android.Io
{
return (!ioc.IsLocalFile()) && (ioc.CredSaveMode != IOCredSaveMode.SaveCred);
}
public void CreateDirectory(IOConnectionInfo ioc)
{
//TODO
throw new NotImplementedException();
}
public IEnumerable<FileDescription> ListContents(IOConnectionInfo ioc)
{
//TODO
throw new NotImplementedException();
}
}
}

View File

@ -88,7 +88,7 @@ namespace keepass2android.Io
File.Delete(BaseVersionFilePath(ioc));
}
_cachedStorage.DeleteFile(ioc);
_cachedStorage.Delete(ioc);
}
private string CachedFilePath(IOConnectionInfo ioc)
@ -105,6 +105,11 @@ namespace keepass2android.Io
&& File.Exists(BaseVersionFilePath(ioc));
}
public void Delete(IOConnectionInfo ioc)
{
_cachedStorage.Delete(ioc);
}
public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion)
{
//see comment in GetCurrentFileVersionFast
@ -416,6 +421,16 @@ namespace keepass2android.Io
return _cachedStorage.RequiresCredentials(ioc);
}
public void CreateDirectory(IOConnectionInfo ioc)
{
_cachedStorage.CreateDirectory(ioc);
}
public IEnumerable<FileDescription> ListContents(IOConnectionInfo ioc)
{
return _cachedStorage.ListContents(ioc);
}
public string GetBaseVersionHash(IOConnectionInfo ioc)
{

View File

@ -22,6 +22,9 @@ namespace keepass2android.Io
{
}
public override IEnumerable<string> SupportedProtocols { get { yield return "dropbox"; } }
protected override string Protocol
{
get { return "dropbox"; }
}
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace keepass2android.Io
{
public class FileDescription
{
public string Path { get; set; }
public bool IsDirectory { get; set; }
public DateTime LastModified { get; set; }
public bool CanRead { get; set; }
public bool CanWrite { get; set; }
public long SizeInBytes { get; set; }
}
}

View File

@ -17,7 +17,7 @@ namespace keepass2android.Io
public class GDriveFileStorage: IFileStorage
{
public IEnumerable<string> SupportedProtocols { get { yield return "gdrive"; } }
public void DeleteFile(IOConnectionInfo ioc)
public void Delete(IOConnectionInfo ioc)
{
throw new NotImplementedException();
}
@ -63,5 +63,15 @@ namespace keepass2android.Io
{
throw new NotImplementedException();
}
public void CreateDirectory(IOConnectionInfo ioc)
{
throw new NotImplementedException();
}
public IEnumerable<FileDescription> ListContents(IOConnectionInfo convertPathToIoc)
{
throw new NotImplementedException();
}
}
}

View File

@ -36,9 +36,9 @@ namespace keepass2android.Io
IEnumerable<string> SupportedProtocols { get; }
/// <summary>
/// Deletes the given file.
/// Deletes the given file or directory.
/// </summary>
void DeleteFile(IOConnectionInfo ioc);
void Delete(IOConnectionInfo ioc);
/// <summary>
/// Tests whether the file was changed.
@ -54,7 +54,7 @@ namespace keepass2android.Io
/// </summary>
/// This string may have a deliberate value (except null) and should not be used by callers except for passing it to
/// CheckForFileChangeFast().
/// <returns>A string which should not be null.</returns>
/// <returns>A string describing the version. Null means, there is no way to get a file version (or it's not implemented).</returns>
string GetCurrentFileVersionFast(IOConnectionInfo ioc);
/// <summary>
@ -96,6 +96,16 @@ namespace keepass2android.Io
/// Returns true if the the given ioc must be filled with username/password
/// </summary>
bool RequiresCredentials(IOConnectionInfo ioc);
/// <summary>
/// Creates the directory described by ioc
/// </summary>
void CreateDirectory(IOConnectionInfo ioc);
/// <summary>
/// Lists the contents of the given path
/// </summary>
IEnumerable<FileDescription> ListContents(IOConnectionInfo ioc);
}
/// <summary>

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Android.App;
using KeePassLib.Serialization;
using KeePassLib.Utility;
@ -12,7 +13,8 @@ namespace keepass2android.Io
{
public abstract class JavaFileStorage: IFileStorage
{
public abstract IEnumerable<string> SupportedProtocols { get; }
public IEnumerable<string> SupportedProtocols { get { yield return Protocol; } }
private readonly IJavaFileStorage _jfs;
private readonly IKp2aApp _app;
@ -23,9 +25,20 @@ namespace keepass2android.Io
_app = app;
}
public void DeleteFile(IOConnectionInfo ioc)
public void Delete(IOConnectionInfo ioc)
{
throw new NotImplementedException();
try
{
Jfs.Delete(IocToPath(ioc));
}
catch (FileNotFoundException e)
{
throw new System.IO.FileNotFoundException(e.Message, e);
}
catch (Java.Lang.Exception e)
{
throw LogAndConvertJavaException(e);
}
}
public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion)
@ -196,14 +209,68 @@ namespace keepass2android.Io
return false;
}
private static string IocToPath(IOConnectionInfo ioc)
public void CreateDirectory(IOConnectionInfo ioc)
{
int protocolLength = ioc.Path.IndexOf("://", StringComparison.Ordinal);
if (protocolLength < 0)
return ioc.Path;
else
return ioc.Path.Substring(protocolLength + 3);
try
{
Jfs.CreateFolder(IocToPath(ioc));
}
catch (FileNotFoundException e)
{
throw new System.IO.FileNotFoundException(e.Message, e);
}
catch (Java.Lang.Exception e)
{
throw LogAndConvertJavaException(e);
}
}
public IEnumerable<FileDescription> ListContents(IOConnectionInfo ioc)
{
try
{
IList<JavaFileStorageFileEntry> entries = Jfs.ListFiles(IocToPath(ioc));
return entries.Select(
e => new FileDescription
{
CanRead = e.CanRead,
CanWrite = e.CanWrite,
IsDirectory = e.IsDirectory,
LastModified = JavaTimeToCSharp(e.LastModifiedTime),
Path = Protocol + "://" + e.Path,
SizeInBytes = e.SizeInBytes
}
);
}
catch (FileNotFoundException e)
{
throw new System.IO.FileNotFoundException(e.Message, e);
}
catch (Java.Lang.Exception e)
{
throw LogAndConvertJavaException(e);
}
}
private DateTime JavaTimeToCSharp(long javatime)
{
//todo test
return new DateTime(1970, 1, 1).AddMilliseconds(javatime);
}
private string IocToPath(IOConnectionInfo ioc)
{
if (ioc.Path.StartsWith(Protocol + "://"))
return ioc.Path.Substring(Protocol.Length + 3);
else
{
return ioc.Path;
}
}
protected abstract string Protocol { get; }
}
}

View File

@ -58,6 +58,7 @@
<Compile Include="Io\BuiltInFileStorage.cs" />
<Compile Include="Io\CachingFileStorage.cs" />
<Compile Include="Io\DropboxFileStorage.cs" />
<Compile Include="Io\FileDescription.cs" />
<Compile Include="Io\GDriveFileStorage.cs" />
<Compile Include="Io\IFileStorage.cs" />
<Compile Include="Io\IoUtil.cs" />

View File

@ -18,11 +18,16 @@ namespace Kp2aUnitTests
{
if (Offline)
throw new IOException("offline");
_builtIn.DeleteFile(ioc);
_builtIn.Delete(ioc);
}
public IFileStorageSetup RequiredSetup { get { return null; } }
public void Delete(IOConnectionInfo ioc)
{
throw new NotImplementedException();
}
public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion)
{
if (Offline)
@ -101,5 +106,15 @@ namespace Kp2aUnitTests
{
return _builtIn.RequiresCredentials(ioc);
}
public void CreateDirectory(IOConnectionInfo ioc)
{
throw new NotImplementedException();
}
public IEnumerable<FileDescription> ListContents(IOConnectionInfo ioc)
{
throw new NotImplementedException();
}
}
}

View File

@ -3,6 +3,7 @@
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="14" />

View File

@ -5,6 +5,7 @@ import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Context;
@ -31,7 +32,10 @@ import com.dropbox.client2.session.Session.AccessType;
public class DropboxFileStorage implements JavaFileStorage {
final static private String APP_KEY = "i8shu7v1hgh7ynt";
//NOTE: also adjust secret!
final static private String APP_KEY = "i8shu7v1hgh7ynt"; //KP2A
//final static private String APP_KEY = "4ybka4p4a1027n6"; //FileStorageTest
// If you'd like to change the access type to the full Dropbox instead of
// an app folder, change this value.
@ -43,8 +47,6 @@ public class DropboxFileStorage implements JavaFileStorage {
final static private String ACCESS_KEY_NAME = "ACCESS_KEY";
final static private String ACCESS_SECRET_NAME = "ACCESS_SECRET";
DropboxAPI<AndroidAuthSession> mApi;
private boolean mLoggedIn = false;
private Context mContext;
@ -117,22 +119,6 @@ public class DropboxFileStorage implements JavaFileStorage {
return mLoggedIn;
}
public ArrayList<String> listContents(String path) throws Exception
{
ArrayList<String> files = new ArrayList<String>();
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 convertException(e);
}
return files;
}
public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception
{
@ -159,7 +145,6 @@ public class DropboxFileStorage implements JavaFileStorage {
public InputStream openFileForRead(String path) throws Exception
{
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
return mApi.getFileStream(path, null);
} catch (DropboxException e) {
@ -187,6 +172,7 @@ public class DropboxFileStorage implements JavaFileStorage {
{
Log.d(TAG, "LoggedIn=false (due to unlink exception)");
setLoggedIn(false);
clearKeys();
return new Exception("Unlinked from Dropbox!", e);
}
@ -272,4 +258,61 @@ public class DropboxFileStorage implements JavaFileStorage {
return session;
}
@Override
public void createFolder(String path) throws Exception {
try
{
mApi.createFolder(path);
}
catch (DropboxException e) {
throw convertException(e);
}
}
@Override
public List<FileEntry> listFiles(String dirName) throws Exception {
try
{
com.dropbox.client2.DropboxAPI.Entry dirEntry = mApi.metadata(dirName, 0, null, true, null);
if (dirEntry.isDeleted)
throw new FileNotFoundException("Directory "+dirName+" is deleted!");
List<FileEntry> result = new ArrayList<FileEntry>();
for (com.dropbox.client2.DropboxAPI.Entry e: dirEntry.contents)
{
if (e.isDeleted)
continue;
FileEntry fileEntry = new FileEntry();
fileEntry.canRead = true;
fileEntry.canWrite = true;
fileEntry.isDirectory = e.isDir;
fileEntry.sizeInBytes = e.bytes;
fileEntry.path = e.path;
fileEntry.lastModifiedTime = com.dropbox.client2.RESTUtility.parseDate(e.modified).getTime();
result.add(fileEntry);
}
return result;
} catch (DropboxException e) {
throw convertException(e);
}
}
@Override
public void delete(String path) throws Exception {
try
{
mApi.delete(path);
} catch (DropboxException e) {
throw convertException(e);
}
}
}

View File

@ -1,17 +1,77 @@
package keepass2android.javafilestorage;
import java.io.InputStream;
import java.util.List;
import android.app.Activity;
public interface JavaFileStorage {
public class FileEntry {
public String path;
public boolean isDirectory;
public long lastModifiedTime;
public boolean canRead;
public boolean canWrite;
public long sizeInBytes;
public FileEntry()
{
isDirectory = false;
canRead = canWrite = true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (canRead ? 1231 : 1237);
result = prime * result + (canWrite ? 1231 : 1237);
result = prime * result + (isDirectory ? 1231 : 1237);
result = prime * result
+ (int) (lastModifiedTime ^ (lastModifiedTime >>> 32));
result = prime * result + ((path == null) ? 0 : path.hashCode());
result = prime * result + (int) (sizeInBytes ^ (sizeInBytes >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
FileEntry other = (FileEntry) obj;
if (canRead != other.canRead)
return false;
if (canWrite != other.canWrite)
return false;
if (isDirectory != other.isDirectory)
return false;
if (lastModifiedTime != other.lastModifiedTime)
return false;
if (path == null) {
if (other.path != null)
return false;
} else if (!path.equals(other.path))
return false;
if (sizeInBytes != other.sizeInBytes)
return false;
return true;
}
}
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);
@ -19,4 +79,11 @@ public interface JavaFileStorage {
public InputStream openFileForRead(String path) throws Exception;
public void uploadFile(String path, byte[] data, boolean writeTransactional) throws Exception;
public void createFolder(String path) throws Exception;
public List<FileEntry> listFiles(String dirName) throws Exception;
public void delete(String path) throws Exception;
}

View File

@ -28,7 +28,7 @@ public class MimeTypes {
/**
* Regular expression for files supported by Keepass2Android.
*/
public static final String REGEX_FILE_TYPE_KEEPASS2ANDROID = "(?si)^.+\\.(kdbx)$";
public static final String REGEX_FILE_TYPE_KEEPASS2ANDROID = "(?si)^.+\\.(kdbx|kdbp)$";
/**

View File

@ -91,8 +91,8 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
getAuthority())
.buildUpon()
.appendPath(
addProtocol(getParentPath(filename))
.toString())
getParentPath(filename)
)
.build(), null);
count = 1; //success
}
@ -146,7 +146,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
.genContentIdUriBase(
getAuthority())
.buildUpon()
.appendPath( addProtocol(newFullName)).build();
.appendPath( newFullName).build();
getContext().getContentResolver().notifyChange(uri, null);
return newUri;
}
@ -235,9 +235,9 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
{
String path = Uri.parse(
uri.getQueryParameter(BaseFile.PARAM_SOURCE)).getPath();
uri.getQueryParameter(BaseFile.PARAM_SOURCE)).toString();
String parentPath = addProtocol(getParentPath(path));
String parentPath = getParentPath(path);
if (parentPath == null)
@ -261,7 +261,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
newRow.add(BaseFile
.genContentIdUriBase(
getAuthority())
.buildUpon().appendPath(addProtocol(parentPath))
.buildUpon().appendPath(parentPath)
.build().toString());
newRow.add(parentPath);
newRow.add(fname);
@ -299,14 +299,14 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
return path;
return path.substring(lastSlashPos+1);
}
/*
private String addProtocol(String path) {
if (path == null)
return null;
if (path.startsWith(getProtocolId()+"://"))
return path;
return getProtocolId()+"://"+path;
}
}*/
/**
* Lists the content of a directory, if available.
@ -366,7 +366,8 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
FileEntry f = files.get(i);
Log.d(CLASSNAME, "listing " + f.path +" for "+dirName);
if (Utils.doLog())
Log.d(CLASSNAME, "listing " + f.path +" for "+dirName);
addFileInfo(matrixCursor, i, f);
}// for files
@ -390,14 +391,14 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
.genContentIdUriBase(
getAuthority())
.buildUpon()
.appendPath(addProtocol(dirName))
.appendPath(dirName)
.appendQueryParameter(BaseFile.PARAM_HAS_MORE_FILES,
Boolean.toString(hasMoreFiles[0])).build()
.toString());
newRow.add(addProtocol(dirName));
newRow.add(dirName);
newRow.add(getName(dirName));
Log.d(CLASSNAME, "Returning name " + getName(dirName)+" for " +addProtocol(dirName));
Log.d(CLASSNAME, "Returning name " + getName(dirName)+" for " +dirName);
}
}
@ -427,9 +428,9 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
newRow.add(BaseFile
.genContentIdUriBase(
getAuthority())
.buildUpon().appendPath(addProtocol(f.path))
.buildUpon().appendPath(f.path)
.build().toString());
newRow.add(addProtocol(f.path));
newRow.add(f.path);
newRow.add(getName(f.path));
newRow.add(f.canRead ? 1 : 0);
newRow.add(f.canWrite ? 1 : 0);
@ -545,24 +546,32 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
* <i>non-null but empty</i> cursor if the source is.
*/
private MatrixCursor doCheckAncestor(Uri uri) {
File source = new File(Uri.parse(
uri.getQueryParameter(BaseFile.PARAM_SOURCE)).getPath());
File target = new File(Uri.parse(
uri.getQueryParameter(BaseFile.PARAM_TARGET)).getPath());
String source = Uri.parse(
uri.getQueryParameter(BaseFile.PARAM_SOURCE)).toString();
String target = Uri.parse(
uri.getQueryParameter(BaseFile.PARAM_TARGET)).toString();
if (source == null || target == null)
return null;
boolean validate = ProviderUtils.getBooleanQueryParam(uri,
BaseFile.PARAM_VALIDATE, true);
if (validate) {
if (!source.isDirectory() || !target.exists())
return null;
//not supported
}
if (source.equals(target.getParentFile())
|| (target.getParent() != null && target.getParent()
.startsWith(source.getAbsolutePath())))
if (!source.endsWith("/"))
source += "/";
String targetParent = getParentPath(target);
if (targetParent != null && targetParent.startsWith(source))
{
if (Utils.doLog())
Log.d(CLASSNAME, source+" is parent of "+target);
return BaseFileProviderUtils.newClosedCursor();
}
if (Utils.doLog())
Log.d(CLASSNAME, source+" is no parent of "+target);
return null;
}// doCheckAncestor()
@ -575,11 +584,10 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
* @return the filename.
*/
private static String extractFile(Uri uri) {
String fileName = Uri.parse(uri.getLastPathSegment()).getPath();
String fileName = Uri.parse(uri.getLastPathSegment()).toString();
if (uri.getQueryParameter(BaseFile.PARAM_APPEND_PATH) != null)
fileName += Uri.parse(
uri.getQueryParameter(BaseFile.PARAM_APPEND_PATH))
.getPath();
uri.getQueryParameter(BaseFile.PARAM_APPEND_PATH)).toString();
if (uri.getQueryParameter(BaseFile.PARAM_APPEND_NAME) != null)
fileName += "/" + uri.getQueryParameter(BaseFile.PARAM_APPEND_NAME);
@ -600,33 +608,29 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
private String getParentPath(String path)
{
path = removeTrailingSlash(path);
path = removeProtocol(path);
if (path.indexOf("://") == -1)
{
Log.d(CLASSNAME, "invalid path: " + path);
return null;
}
String pathWithoutProtocol = path.substring(path.indexOf("://")+3);
int lastSlashPos = path.lastIndexOf("/");
if (lastSlashPos == -1)
if (pathWithoutProtocol.indexOf("/") == -1)
{
Log.d(CLASSNAME, "parent of " + path +" is null");
return null;
}
else
return path.substring(0, lastSlashPos)+"/";
{
String parent = path.substring(0, lastSlashPos)+"/";
Log.d(CLASSNAME, "parent of " + path +" is "+parent);
return parent;
}
}
private String removeProtocol(String path) {
if (path.lastIndexOf("://") == -1)
return path;
if (!path.startsWith(getProtocolId()+"://"))
{
String msg = path+" does not start with "+getProtocolId();
Log.d(CLASSNAME, msg);
throw new IllegalArgumentException(msg);
}
return path.substring(getProtocolId().length()+3);
}
protected String getRootDirectory(String currentPath)
{
return getProtocolId() + ":///";
}
protected FileEntry getFileEntry(String path) {
protected FileEntry getFileEntry(String path) {
FileEntry f = new FileEntry();
f.path = path;
f.isDirectory = path.lastIndexOf(".") == -1;
@ -667,6 +671,6 @@ public abstract class Kp2aFileProvider extends BaseFileProvider {
protected abstract boolean deletePath(String filename, boolean isRecursive);
protected abstract boolean createDirectory(String dirname, String newDirName);
protected abstract String getProtocolId();
}

View File

@ -621,7 +621,7 @@ namespace keepass2android
case (int)Result.Ok:
if (requestCode == Intents.RequestCodeFileBrowseForBinary)
{
string filename = Util.IntentToFilename(data);
string filename = Util.IntentToFilename(data, this);
if (filename != null) {
if (filename.StartsWith("file://")) {
filename = filename.Substring(7);

View File

@ -176,7 +176,7 @@ namespace keepass2android
break;
case Result.Ok: // Key file browse dialog OK'ed.
if (requestCode == Intents.RequestCodeFileBrowseForKeyfile) {
string filename = Util.IntentToFilename(data);
string filename = Util.IntentToFilename(data, this);
if (filename != null) {
if (filename.StartsWith("file://")) {
filename = filename.Substring(7);

View File

@ -1,62 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="23"
android:versionName="0.8.6"
package="keepass2android.keepass2android"
android:installLocation="auto">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="23" android:versionName="0.8.6" package="keepass2android.keepass2android" android:installLocation="auto">
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="14" />
<application android:label="keepass2android" android:icon="@drawable/ic_launcher">
<activity
android:name="com.dropbox.client2.android.AuthActivity"
android:launchMode="singleTask"
android:configChanges="orientation|keyboard">
<activity android:name="com.dropbox.client2.android.AuthActivity" android:launchMode="singleTask" android:configChanges="orientation|keyboard">
<intent-filter>
<!-- Change this to be db- followed by your app key -->
<data android:scheme="db-i8shu7v1hgh7ynt" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:configChanges="keyboardHidden|orientation" android:label="@string/app_name" android:theme="@style/Base" android:name="keepass2android.PasswordActivity" >
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:mimeType="*/*" />
<data android:host="*" />
<data android:pathPattern=".*\\.kdbp" />
<data android:pathPattern=".*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\.kdbx" />
<data android:pathPattern=".*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
</intent-filter>
<provider android:name="group.pals.android.lib.ui.filechooser.providers.localfile.LocalFileProvider" android:authorities="keepass2android.keepass2android.android-filechooser.localfile" android:exported="false" />
<provider android:name="group.pals.android.lib.ui.filechooser.providers.history.HistoryProvider" android:authorities="keepass2android.keepass2android.android-filechooser.history" android:exported="false" />
<activity android:name="group.pals.android.lib.ui.filechooser.FileChooserActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:screenOrientation="user" android:theme="@style/Afc.Theme.Light" />
<activity android:configChanges="keyboardHidden|orientation" android:label="@string/app_name" android:theme="@style/Base" android:name="keepass2android.PasswordActivity">
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:mimeType="*/*" />
<data android:host="*" />
<data android:pathPattern=".*\\.kdbp" />
<data android:pathPattern=".*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\.kdbx" />
<data android:pathPattern=".*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
</intent-filter>
</activity>
<service android:name="keepass2android.softkeyboard.KP2AKeyboard"
android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod" />
</intent-filter>
<meta-data android:name="android.view.im" android:resource="@xml/method" />
</service>
<service android:name="keepass2android.softkeyboard.KP2AKeyboard" android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod" />
</intent-filter>
<meta-data android:name="android.view.im" android:resource="@xml/method" />
</service>
</application>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,7 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -27,6 +28,7 @@ using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Content.PM;
using Uri = Android.Net.Uri;
namespace keepass2android
{
@ -159,8 +161,16 @@ namespace keepass2android
}
}
public static string IntentToFilename(Intent data)
public static string IntentToFilename(Intent data, Context ctx)
{
string EXTRA_RESULTS = "group.pals.android.lib.ui.filechooser.FileChooserActivity.results";
if (data.HasExtra(EXTRA_RESULTS))
{
IList uris = data.GetParcelableArrayListExtra(EXTRA_RESULTS);
Uri uri = (Uri) uris[0];
return Group.Pals.Android.Lib.UI.Filechooser.Providers.BaseFileProviderUtils.GetRealUri(ctx, uri).ToString();
}
String filename = data.Data.Path;
if (String.IsNullOrEmpty(filename))
filename = data.DataString;

View File

@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using Android.Content;
using KeePassLib.Serialization;
using Keepass2android.Kp2afilechooser;
using keepass2android.Io;
namespace keepass2android
{
[ContentProvider(new[] { "keepass2android." + AppNames.PackagePart + ".kp2afilechooser.kp2afile" }, Exported = false)]
public class FileChooserFileProvider : Kp2aFileProvider
{
/*int taskId, final String dirName,
final boolean showHiddenFiles, final int filterMode,
final int limit, String positiveRegex, String negativeRegex,
final List<FileEntry> results, final boolean hasMoreFiles[]*/
public override string Authority
{
get { return TheAuthority; }
}
public static string TheAuthority
{
get { return "keepass2android." + AppNames.PackagePart + ".kp2afilechooser.kp2afile"; }
}
protected override bool CreateDirectory(string parentDirectory, string newDirName)
{
try
{
parentDirectory = parentDirectory.TrimEnd('/');
App.Kp2a.GetFileStorage(parentDirectory).CreateDirectory(ConvertPathToIoc(parentDirectory + "/" + newDirName));
return true;
}
catch (Exception e)
{
Kp2aLog.Log(e.ToString());
return false;
}
}
private IOConnectionInfo ConvertPathToIoc(string path)
{
return new IOConnectionInfo() { Path = path };
}
protected override bool DeletePath(string path, bool recursive)
{
try
{
App.Kp2a.GetFileStorage(path).Delete(ConvertPathToIoc(path));
return true;
}
catch(Exception e)
{
Kp2aLog.Log(e.ToString());
return false;
}
}
protected override void ListFiles(int taskId, string dirName, bool showHiddenFiles, int filterMode, int limit, string positiveRegex,
string negativeRegex, IList<FileEntry> fileList, bool[] hasMoreFiles)
{
try
{
var dirContents = App.Kp2a.GetFileStorage(dirName).ListContents(ConvertPathToIoc(dirName));
foreach (FileDescription e in dirContents)
{
fileList.Add(new FileEntry
{
CanRead = e.CanRead,
CanWrite = e.CanWrite,
IsDirectory = e.IsDirectory,
LastModifiedTime = CSharpTimeToJava(e.LastModified),
Path = e.Path,
SizeInBytes = e.SizeInBytes
}
);
}
}
catch (Exception e)
{
Kp2aLog.Log(e.ToString());
}
}
private long CSharpTimeToJava(DateTime dateTime)
{
try
{
return (long)dateTime.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds;
}
catch (Exception)
{
return -1;
}
}
}
}

View File

@ -357,7 +357,7 @@ namespace keepass2android
GroupActivity.Launch(_activity, _activity.AppTask);
} else {
App.Kp2a.GetFileStorage(_ioc).DeleteFile(_ioc);
App.Kp2a.GetFileStorage(_ioc).Delete(_ioc);
}
}
@ -481,17 +481,16 @@ namespace keepass2android
if (resultCode == KeePass.ExitFileStorageSelectionOk)
{
LaunchPasswordActivityForIoc(new IOConnectionInfo()
{
Path = data.GetStringExtra("protocolId")+":///keepass/keepass.kdbx"
}
);
Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(this, FileChooserFileProvider.TheAuthority, data.GetStringExtra("protocolId")+":///");
StartActivityForResult(i, Intents.RequestCodeFileBrowseForOpen);
}
if ( (requestCode == Intents.RequestCodeFileBrowseForCreate
|| requestCode == Intents.RequestCodeFileBrowseForOpen)
&& resultCode == Result.Ok) {
string filename = Util.IntentToFilename(data);
string filename = Util.IntentToFilename(data, this);
if (filename != null) {
if (filename.StartsWith("file://")) {
filename = filename.Substring(7);

View File

@ -78,6 +78,7 @@
<Reference Include="Mono.Android.Support.v4" />
</ItemGroup>
<ItemGroup>
<Compile Include="fileselect\FileChooserFileProvider.cs" />
<Compile Include="FileStorageSelectionActivity.cs" />
<Compile Include="DonateReminder.cs" />
<Compile Include="app\ApplicationBroadcastReceiver.cs" />
@ -656,6 +657,14 @@
<Folder Include="SupportLib\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AndroidFileChooserBinding\AndroidFileChooserBinding.csproj">
<Project>{3c0f7fe5-639f-4422-a087-8b26cf862d1b}</Project>
<Name>AndroidFileChooserBinding</Name>
</ProjectReference>
<ProjectReference Include="..\AppCompatV7Binding\AppCompatV7Binding.csproj">
<Project>{23233a28-d74f-4bf8-b4d8-834060840bd7}</Project>
<Name>AppCompatV7Binding</Name>
</ProjectReference>
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj">
<Project>{48574278-4779-4b3a-a9e4-9cf1bc285d0b}</Project>
<Name>JavaFileStorageBindings</Name>

View File

@ -22,7 +22,6 @@ using Android.OS;
using Android.Widget;
using keepass2android.view;
using KeePassLib;
using Android.Support.V4.App;
namespace keepass2android.search
{