BIN
										
									
								
								graphics/launcher_icon/Logo-green-96.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								graphics/launcher_icon/Logo-green-96.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.3 KiB | 
							
								
								
									
										64
									
								
								src/AdalBindings/AdalBindings.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/AdalBindings/AdalBindings.csproj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| <?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>{0B109C0E-0514-4340-8779-5BD6A0DDE84E}</ProjectGuid> | ||||
|     <ProjectTypeGuids>{10368E6C-D01B-4462-8E8B-01FC667A7035};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> | ||||
|     <OutputType>Library</OutputType> | ||||
|     <AppDesignerFolder>Properties</AppDesignerFolder> | ||||
|     <RootNamespace>AdalBindings</RootNamespace> | ||||
|     <AssemblyName>AdalBindings</AssemblyName> | ||||
|     <FileAlignment>512</FileAlignment> | ||||
|     <AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk> | ||||
|     <TargetFrameworkVersion>v8.1</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="Jars\adal-1.14.0.aar" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <TransformFile Include="Transforms\Metadata.xml" /> | ||||
|     <TransformFile Include="Transforms\EnumFields.xml" /> | ||||
|     <TransformFile Include="Transforms\EnumMethods.xml" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <EmbeddedReferenceJar Include="Jars\gson-2.3.1.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> | ||||
							
								
								
									
										48
									
								
								src/AdalBindings/Additions/AboutAdditions.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/AdalBindings/Additions/AboutAdditions.txt
									
									
									
									
									
										Normal 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; } | ||||
| } | ||||
							
								
								
									
										24
									
								
								src/AdalBindings/Jars/AboutJars.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/AdalBindings/Jars/AboutJars.txt
									
									
									
									
									
										Normal 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". | ||||
							
								
								
									
										
											BIN
										
									
								
								src/AdalBindings/Jars/gson-2.3.1.jar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/AdalBindings/Jars/gson-2.3.1.jar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										30
									
								
								src/AdalBindings/Properties/AssemblyInfo.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/AdalBindings/Properties/AssemblyInfo.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| 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("AdalBindings")] | ||||
| [assembly: AssemblyDescription("")] | ||||
| [assembly: AssemblyConfiguration("")] | ||||
| [assembly: AssemblyCompany("")] | ||||
| [assembly: AssemblyProduct("AdalBindings")] | ||||
| [assembly: AssemblyCopyright("Copyright ©  2018")] | ||||
| [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")] | ||||
							
								
								
									
										14
									
								
								src/AdalBindings/Transforms/EnumFields.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/AdalBindings/Transforms/EnumFields.xml
									
									
									
									
									
										Normal 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> | ||||
							
								
								
									
										13
									
								
								src/AdalBindings/Transforms/EnumMethods.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/AdalBindings/Transforms/EnumMethods.xml
									
									
									
									
									
										Normal 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> | ||||
							
								
								
									
										13
									
								
								src/AdalBindings/Transforms/Metadata.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/AdalBindings/Transforms/Metadata.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| <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']" /> | ||||
|   --> | ||||
|   <remove-node path="/api/package[@name='com.microsoft.aad.adal']/class[@name='AuthenticationActivity']" /> | ||||
|   <remove-node path="/api/package[@name='com.microsoft.aad.adal']/class[@name='DateTimeAdapter']" /> | ||||
|   <remove-node path="/api/package[@name='com.microsoft.aad.adal']" /> | ||||
|  | ||||
| </metadata> | ||||
| @@ -60,7 +60,6 @@ | ||||
|     </LibraryProjectZip> | ||||
|     <None Include="Jars\AboutJars.txt" /> | ||||
|     <None Include="Additions\AboutAdditions.txt" /> | ||||
|     <LibraryProjectZip Include="Jars\adal-1.14.0.aar" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <TransformFile Include="Transforms\Metadata.xml" /> | ||||
| @@ -82,6 +81,10 @@ | ||||
|     </XamarinComponentReference> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\AdalBindings\AdalBindings.csproj"> | ||||
|       <Project>{0b109c0e-0514-4340-8779-5bd6a0dde84e}</Project> | ||||
|       <Name>AdalBindings</Name> | ||||
|     </ProjectReference> | ||||
|     <ProjectReference Include="..\PCloudBindings\PCloudBindings.csproj" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
| @@ -153,4 +156,4 @@ | ||||
|   <ItemGroup> | ||||
|     <EmbeddedReferenceJar Include="Jars\okio-1.13.0.jar" /> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
| </Project> | ||||
| @@ -11,6 +11,8 @@ | ||||
| 	<remove-node path="/api/package[@name='com.jcraft.jsch.jcraft']" /> | ||||
| 	<remove-node path="/api/package[@name='com.jcraft.jzlib']" /> | ||||
|  | ||||
|   <remove-node path="/api/package[@name='com.pcloud.sdk']" /> | ||||
|  | ||||
|   <remove-node path="/api/package[@name='com.dropbox.core']" /> | ||||
|   <remove-node path="/api/package[@name='com.dropbox.core.util']" /> | ||||
|   <remove-node path="/api/package[@name='com.dropbox.core.http']" /> | ||||
|   | ||||
| @@ -29,6 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamsungPass", "SamsungPass\ | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PCloudBindings", "PCloudBindings\PCloudBindings.csproj", "{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdalBindings", "AdalBindings\AdalBindings.csproj", "{0B109C0E-0514-4340-8779-5BD6A0DDE84E}" | ||||
| EndProject | ||||
| Global | ||||
| 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
| 		Debug|Any CPU = Debug|Any CPU | ||||
| @@ -158,19 +160,25 @@ Global | ||||
| 		{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|Win32.Build.0 = Debug|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|x64.Build.0 = 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|Win32.Build.0 = 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}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Win32.Build.0 = ReleaseNoNet|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|x64.Build.0 = ReleaseNoNet|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 | ||||
| @@ -285,16 +293,54 @@ Global | ||||
| 		{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU | ||||
| 		{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU | ||||
| 		{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Win32.Build.0 = Debug|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|x64.Build.0 = Debug|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Win32.Build.0 = Release|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Win32.Build.0 = ReleaseNoNet|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU | ||||
| 		{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|x64.Build.0 = ReleaseNoNet|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Win32.ActiveCfg = Debug|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Win32.Build.0 = Debug|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|x64.Build.0 = Debug|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Mixed Platforms.Build.0 = Release|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Win32.ActiveCfg = Release|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Win32.Build.0 = Release|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|x64.ActiveCfg = Release|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Win32.Build.0 = ReleaseNoNet|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU | ||||
| 		{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|x64.Build.0 = ReleaseNoNet|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|Win32.ActiveCfg = Debug|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|Win32.Build.0 = Debug|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|x64.Build.0 = Debug|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|Mixed Platforms.Build.0 = Release|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|Win32.ActiveCfg = Release|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|Win32.Build.0 = Release|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|x64.ActiveCfg = Release|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|Win32.Build.0 = Release|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU | ||||
| 		{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|x64.Build.0 = Release|Any CPU | ||||
| 	EndGlobalSection | ||||
| 	GlobalSection(SolutionProperties) = preSolution | ||||
| 		HideSolutionNode = FALSE | ||||
|   | ||||
| @@ -5,8 +5,8 @@ namespace keepass2android.Io | ||||
| { | ||||
| 	public class SftpFileStorage: JavaFileStorage | ||||
| 	{ | ||||
| 		public SftpFileStorage(IKp2aApp app) : | ||||
| 			base(new Keepass2android.Javafilestorage.SftpStorage(), app) | ||||
| 		public SftpFileStorage(Context ctx, IKp2aApp app) : | ||||
| 			base(new Keepass2android.Javafilestorage.SftpStorage(ctx.ApplicationContext), app) | ||||
| 		{ | ||||
| 		} | ||||
|  | ||||
|   | ||||
| @@ -156,6 +156,10 @@ | ||||
|     <Compile Include="Utils\Spr\SprEngine.PickChars.cs" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\AdalBindings\AdalBindings.csproj"> | ||||
|       <Project>{0b109c0e-0514-4340-8779-5bd6a0dde84e}</Project> | ||||
|       <Name>AdalBindings</Name> | ||||
|     </ProjectReference> | ||||
|     <ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj"> | ||||
|       <Project>{48574278-4779-4b3a-a9e4-9cf1bc285d0b}</Project> | ||||
|       <Name>JavaFileStorageBindings</Name> | ||||
|   | ||||
| @@ -63,8 +63,9 @@ | ||||
|     <TransformFile Include="Transforms\EnumMethods.xml" /> | ||||
|     <TransformFile Include="Transforms\Metadata.xml" /> | ||||
|   </ItemGroup> | ||||
|   <Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" /> | ||||
|   <ItemGroup> | ||||
|     <Folder Include="libs\" /> | ||||
|   </ItemGroup> | ||||
|   <Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" /> | ||||
|    | ||||
| </Project> | ||||
|   | ||||
| @@ -4,8 +4,13 @@ | ||||
|     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||||
|     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||||
|     <ProjectGuid>{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}</ProjectGuid> | ||||
|     <ProjectTypeGuids>{6322E8A7-5C46-4E8C-8B19-448B7BC95DC1};{E1126D83-ADAB-4E4F-81F7-4B0A645A68C7}</ProjectTypeGuids> | ||||
|  | ||||
|     <ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{10368E6C-D01B-4462-8E8B-01FC667A7035};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> | ||||
|     <OutputType>Library</OutputType> | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     <AppDesignerFolder>Properties</AppDesignerFolder> | ||||
|     <RootNamespace>PCloudBindings</RootNamespace> | ||||
|     <AssemblyName>PCouldBindings</AssemblyName> | ||||
| @@ -21,6 +26,7 @@ | ||||
|     <DefineConstants>DEBUG;TRACE</DefineConstants> | ||||
|     <ErrorReport>prompt</ErrorReport> | ||||
|     <WarningLevel>0</WarningLevel> | ||||
|  | ||||
|     <AndroidLinkMode>None</AndroidLinkMode> | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||||
| @@ -31,6 +37,7 @@ | ||||
|     <ErrorReport>prompt</ErrorReport> | ||||
|     <WarningLevel>4</WarningLevel> | ||||
|     <AndroidUseSharedRuntime>false</AndroidUseSharedRuntime> | ||||
|  | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseNoNet|AnyCPU'"> | ||||
|     <OutputPath>bin\ReleaseNoNet\</OutputPath> | ||||
| @@ -46,12 +53,18 @@ | ||||
|   <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="Jars\pcloud-sdk-android-1.0.1.aar" /> | ||||
| @@ -60,6 +73,7 @@ | ||||
|     <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.  | ||||
| @@ -72,4 +86,5 @@ | ||||
|   <ItemGroup> | ||||
|     <EmbeddedReferenceJar Include="Jars\pcloud-sdk-java-core-1.0.1.jar" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
| </Project> | ||||
|   | ||||
| @@ -6,4 +6,5 @@ | ||||
|   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']" /> | ||||
|   --> | ||||
|   <remove-node path="/api/package[@name='com.pcloud.sdk']" /> | ||||
| </metadata> | ||||
|   | ||||
| @@ -53,8 +53,8 @@ | ||||
|     <Compile Include="Properties\AssemblyInfo.cs" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <LibraryProjectZip Include="..\java\Keepass2AndroidPluginSDK2\app\build\outputs\aar\app-debug.aar"> | ||||
|       <Link>Jars\app-debug.aar</Link> | ||||
|     <LibraryProjectZip Include="..\java\Keepass2AndroidPluginSDK2\app\build\outputs\aar\app-release.aar"> | ||||
|       <Link>Jars\app-release.aar</Link> | ||||
|     </LibraryProjectZip> | ||||
|     <None Include="Jars\AboutJars.txt" /> | ||||
|     <None Include="Additions\AboutAdditions.txt" /> | ||||
|   | ||||
| @@ -1,15 +1,21 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     package="keepass2android.javafilestorage" | ||||
|     android:versionCode="1" | ||||
|     android:versionName="1.0"> | ||||
|  | ||||
|      | ||||
|     <uses-sdk | ||||
|         android:minSdkVersion="8" | ||||
|         android:targetSdkVersion="14" /> | ||||
|      | ||||
|  | ||||
|     <uses-permission android:name="android.permission.GET_ACCOUNTS"/> | ||||
|     <uses-permission android:name="android.permission.GET_ACCOUNTS" /> | ||||
|  | ||||
| </manifest> | ||||
|  | ||||
|     <application> | ||||
|         <activity | ||||
|             android:name=".NotifSlave" | ||||
|             android:label="Keepass2Android"></activity> | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
| @@ -0,0 +1,169 @@ | ||||
| package keepass2android.javafilestorage; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.app.AlertDialog; | ||||
| import android.app.Dialog; | ||||
| import android.content.DialogInterface; | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| import android.os.Message; | ||||
| import android.os.Messenger; | ||||
| import android.util.Log; | ||||
| import android.view.View; | ||||
| import android.widget.Button; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
|  | ||||
| //based on https://github.com/jwise/dumload/blob/master/src/com/joshuawise/dumload/NotifSlave.java | ||||
| public class NotifSlave extends Activity { | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|     } | ||||
|  | ||||
|     private void say(String s) { | ||||
|         Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT).show(); | ||||
|     } | ||||
|  | ||||
|     private int _nextdialog = 0; | ||||
|     private Dialog dialog = null; | ||||
|  | ||||
|     @Override | ||||
|     protected Dialog onCreateDialog(int id) | ||||
|     { | ||||
|         Log.e("KP2AJ.NotifSlave", "Create for dialog "+(Integer.toString(id))); | ||||
|         if (id != _nextdialog) | ||||
|             return null; | ||||
|         return dialog; | ||||
|     } | ||||
|  | ||||
|     private void showDialog(Dialog d) | ||||
|     { | ||||
|         _nextdialog++; | ||||
|         dialog = d; | ||||
|         Log.e("KP2AJ.NotifSlave", "Attempting to show dialog "+(Integer.toString(_nextdialog))); | ||||
|         showDialog(_nextdialog); | ||||
|     } | ||||
|  | ||||
|     public void onStart() { | ||||
|         super.onStart(); | ||||
|  | ||||
|         Intent i = getIntent(); /* i *am* not an intent! */ | ||||
|         final Activity thisact = this; | ||||
|  | ||||
|         final Messenger m = (Messenger)i.getParcelableExtra("keepass2android.sftp.returnmessenger"); | ||||
|         String reqtype = i.getStringExtra("keepass2android.sftp.reqtype"); | ||||
|         String prompt = i.getStringExtra("keepass2android.sftp.prompt"); | ||||
|  | ||||
|         if (prompt == null || reqtype == null || m == null)	/* i.e., we got called by a dummy notification */ | ||||
|         { | ||||
|             this.finish(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (reqtype.equals("yesno")) { | ||||
|             AlertDialog.Builder builder = new AlertDialog.Builder(this); | ||||
|             builder.setTitle("Keepass2Android"); | ||||
|             builder.setMessage(prompt); | ||||
|             builder.setCancelable(false); | ||||
|             builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { | ||||
|                 public void onClick(DialogInterface dialog, int id) { | ||||
|                     Log.e("KP2AJ.NotifSlave", "Responding with a 1."); | ||||
|                     try { | ||||
|                         Message me = Message.obtain(); | ||||
|                         me.arg1 = 1; | ||||
|                         m.send(me); | ||||
|                     } catch (Exception e) { | ||||
|                         Log.e("KP2AJ.NotifSlave", "Failed to send a message back to my buddy."); | ||||
|                     } | ||||
|                     dialog.cancel(); | ||||
|                     thisact.finish(); | ||||
|                 } | ||||
|             }); | ||||
|             builder.setNegativeButton("No", new DialogInterface.OnClickListener() { | ||||
|                 public void onClick(DialogInterface dialog, int id) { | ||||
|                     Log.e("KP2AJ.NotifSlave", "Responding with a 1."); | ||||
|                     try { | ||||
|                         Message me = Message.obtain(); | ||||
|                         me.arg1 = 0; | ||||
|                         m.send(me); | ||||
|                     } catch (Exception e) { | ||||
|                         Log.e("KP2AJ.NotifSlave", "Failed to send a message back to my buddy."); | ||||
|                     } | ||||
|                     dialog.cancel(); | ||||
|                     thisact.finish(); | ||||
|                 } | ||||
|             }); | ||||
|             AlertDialog alert = builder.create(); | ||||
|             showDialog(alert); | ||||
|         } else if (reqtype.equals("message")) { | ||||
|             AlertDialog.Builder builder = new AlertDialog.Builder(this); | ||||
|             builder.setTitle("Keepass2Android"); | ||||
|             builder.setMessage(prompt); | ||||
|             builder.setCancelable(false); | ||||
|             builder.setNeutralButton("OK", new DialogInterface.OnClickListener() { | ||||
|                 public void onClick(DialogInterface dialog, int id) { | ||||
|                     try { | ||||
|                         Message me = Message.obtain(); | ||||
|                         m.send(me); | ||||
|                     } catch (Exception e) { | ||||
|                         Log.e("KP2AJ.NotifSlave", "Failed to send a message back to my buddy."); | ||||
|                     } | ||||
|                     dialog.cancel(); | ||||
|                     thisact.finish(); | ||||
|                 } | ||||
|             }); | ||||
|             AlertDialog alert = builder.create(); | ||||
|             showDialog(alert); | ||||
|         } /*else if (reqtype.equals("password")) { | ||||
|             final Dialog d = new Dialog(this); | ||||
|  | ||||
|             d.setContentView(R.layout.notfif_slave); | ||||
|             d.setTitle("Keepass2Android"); | ||||
|             d.setCancelable(false); | ||||
|  | ||||
|             TextView text = (TextView) d.findViewById(R.id.prompt); | ||||
|             text.setText(prompt); | ||||
|  | ||||
|             Button ok = (Button) d.findViewById(R.id.ok); | ||||
|             ok.setOnClickListener(new View.OnClickListener() { | ||||
|                 public void onClick(View v) { | ||||
|                     try { | ||||
|                         Message me = Message.obtain(); | ||||
|                         me.arg1 = 1; | ||||
|                         TextView entry = (TextView) d.findViewById(R.id.entry); | ||||
|                         Bundle b = new Bundle(1); | ||||
|                         b.putString("response", entry.getText().toString()); | ||||
|                         me.setData(b); | ||||
|                         m.send(me); | ||||
|                     } catch (Exception e) { | ||||
|                         Log.e("KP2AJ.NotifSlave", "Failed to send a message back to my buddy."); | ||||
|                     } | ||||
|                     d.cancel(); | ||||
|                     thisact.finish(); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             Button cancel = (Button) d.findViewById(R.id.cancel); | ||||
|             cancel.setOnClickListener(new View.OnClickListener() { | ||||
|                 public void onClick(View v) { | ||||
|                     try { | ||||
|                         Message me = Message.obtain(); | ||||
|                         me.arg1 = 0; | ||||
|                         m.send(me); | ||||
|                     } catch (Exception e) { | ||||
|                         Log.e("KP2AJ.NotifSlave", "Failed to send a message back to my buddy."); | ||||
|                     } | ||||
|                     d.cancel(); | ||||
|                     thisact.finish(); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|  | ||||
|             showDialog(d); | ||||
|         } */else { | ||||
|             Log.e("KP2AJ.NotifSlave", "What's a "+reqtype+"?"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -2,7 +2,9 @@ package keepass2android.javafilestorage; | ||||
|  | ||||
| import java.io.ByteArrayInputStream; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.File; | ||||
| import java.io.FileNotFoundException; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.UnsupportedEncodingException; | ||||
| import java.util.ArrayList; | ||||
| @@ -13,6 +15,7 @@ import com.jcraft.jsch.ChannelSftp; | ||||
| import com.jcraft.jsch.ChannelSftp.LsEntry; | ||||
| import com.jcraft.jsch.JSch; | ||||
| import com.jcraft.jsch.JSchException; | ||||
| import com.jcraft.jsch.KeyPair; | ||||
| import com.jcraft.jsch.Session; | ||||
| import com.jcraft.jsch.SftpATTRS; | ||||
| import com.jcraft.jsch.SftpException; | ||||
| @@ -21,6 +24,7 @@ import com.jcraft.jsch.UserInfo; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| import android.support.annotation.NonNull; | ||||
|  | ||||
| public class SftpStorage extends JavaFileStorageBase { | ||||
|  | ||||
| @@ -35,8 +39,10 @@ public class SftpStorage extends JavaFileStorageBase { | ||||
| 		public String localPath; | ||||
| 		public int port; | ||||
| 	} | ||||
| 	Context _appContext; | ||||
|  | ||||
| 	public SftpStorage() { | ||||
| 	public SftpStorage(Context appContext) { | ||||
| 		_appContext = appContext; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| @@ -318,12 +324,28 @@ public class SftpStorage extends JavaFileStorageBase { | ||||
| 		jsch = new JSch(); | ||||
| 		ConnectionInfo ci = splitStringToConnectionInfo(filename); | ||||
|  | ||||
| 		String base_dir = getBaseDir(); | ||||
| 		jsch.setKnownHosts(base_dir + "/known_hosts"); | ||||
|  | ||||
| 		String key_filename = getKeyFileName(); | ||||
| 		try{ | ||||
| 			createKeyPair(key_filename); | ||||
| 		} catch (Exception ex) { | ||||
| 			System.out.println(ex); | ||||
| 		} | ||||
|  | ||||
| 		try { | ||||
| 			jsch.addIdentity(key_filename); | ||||
| 		} catch (java.lang.Exception e) | ||||
| 		{ | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		Session session = jsch.getSession(ci.username, ci.host, ci.port); | ||||
| 		UserInfo ui = new SftpUserInfo(ci.password); | ||||
| 		UserInfo ui = new SftpUserInfo(ci.password,_appContext); | ||||
| 		session.setUserInfo(ui); | ||||
|  | ||||
| 		session.setConfig("PreferredAuthentications", | ||||
| 				"password,publickey"); | ||||
| 		session.setConfig("PreferredAuthentications", "publickey,password"); | ||||
|  | ||||
| 		session.connect(); | ||||
|  | ||||
| @@ -336,6 +358,37 @@ public class SftpStorage extends JavaFileStorageBase { | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	@NonNull | ||||
| 	private String getBaseDir() { | ||||
| 		return _appContext.getFilesDir().getAbsolutePath(); | ||||
| 	} | ||||
|  | ||||
| 	@NonNull | ||||
| 	private String getKeyFileName() { | ||||
| 		return getBaseDir() + "/id_kp2a_rsa"; | ||||
| 	} | ||||
|  | ||||
| 	public String createKeyPair() throws IOException, JSchException { | ||||
| 		return createKeyPair(getKeyFileName()); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	private String createKeyPair(String key_filename) throws JSchException, IOException { | ||||
| 		String public_key_filename = key_filename + ".pub"; | ||||
| 		File file = new File(key_filename); | ||||
| 		if (file.exists()) | ||||
| 			return public_key_filename; | ||||
| 		int type = KeyPair.RSA; | ||||
| 		KeyPair kpair = KeyPair.genKeyPair(jsch, type, 2048); | ||||
| 		kpair.writePrivateKey(key_filename); | ||||
|  | ||||
| 		kpair.writePublicKey(public_key_filename, "generated by Keepass2Android"); | ||||
| 		//ret = "Fingerprint: " + kpair.getFingerPrint(); | ||||
| 		kpair.dispose(); | ||||
| 		return public_key_filename; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	public ConnectionInfo splitStringToConnectionInfo(String filename) | ||||
| 			throws UnsupportedEncodingException { | ||||
| 		ConnectionInfo ci = new ConnectionInfo(); | ||||
|   | ||||
| @@ -1,14 +1,119 @@ | ||||
| package keepass2android.javafilestorage; | ||||
|  | ||||
| import android.app.Notification; | ||||
| import android.app.NotificationManager; | ||||
| import android.app.PendingIntent; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.os.Handler; | ||||
| import android.os.Looper; | ||||
| import android.os.Message; | ||||
| import android.os.Messenger; | ||||
| import android.os.SystemClock; | ||||
| import android.support.v4.app.NotificationCompat; | ||||
| import android.util.Log; | ||||
|  | ||||
| import com.jcraft.jsch.UserInfo; | ||||
|  | ||||
| public class SftpUserInfo implements UserInfo { | ||||
|  | ||||
| 	private Object /* pick one type, and fixate on it */ dance(final String type, final String text)	/* for inside the thread */ | ||||
| 	{ | ||||
|  | ||||
| 		final Message msg = Message.obtain(); | ||||
|  | ||||
| 		/* t(*A*t) */ | ||||
| 		Thread t = new Thread() { | ||||
| 			public void run() { | ||||
| 				Looper.prepare(); | ||||
| 				int bogon = (int)SystemClock.elapsedRealtime(); | ||||
|  | ||||
| 				NotificationManager mNotificationManager = (NotificationManager)_appContext.getSystemService(Context.NOTIFICATION_SERVICE); | ||||
| 				NotificationCompat.Builder builder = new NotificationCompat.Builder(_appContext); | ||||
| 				builder.setContentText("SFTP prompt"); | ||||
| 				builder.setSmallIcon(R.drawable.ic_logo_green_foreground); | ||||
|  | ||||
|  | ||||
| 				Handler h = new Handler() { | ||||
| 					public void handleMessage(Message M) { | ||||
| 						msg.copyFrom(M); | ||||
| 						Looper.myLooper().quit(); | ||||
| 					} | ||||
| 				}; | ||||
| 				Messenger m = new Messenger(h); | ||||
|  | ||||
| 				Intent intent = new Intent(_appContext, NotifSlave.class); | ||||
|  | ||||
| 				intent.setAction("keepass2android.sftp.NotifSlave"); | ||||
| 				intent.putExtra("keepass2android.sftp.returnmessenger", m); | ||||
| 				intent.putExtra("keepass2android.sftp.reqtype", type); | ||||
| 				intent.putExtra("keepass2android.sftp.prompt", text); | ||||
| 				intent.setData((Uri.parse("suckit://"+SystemClock.elapsedRealtime()))); | ||||
|  | ||||
| 				PendingIntent contentIntent = PendingIntent.getActivity(_appContext, 0, intent, 0); | ||||
| 				builder.setContentIntent(contentIntent); | ||||
|  | ||||
| 				{ | ||||
| 					Intent directIntent = new Intent(_appContext, NotifSlave.class); | ||||
| 					directIntent.setAction("keepass2android.sftp.NotifSlave"); | ||||
| 					directIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|  | ||||
| 					directIntent.putExtra("keepass2android.sftp.returnmessenger", m); | ||||
| 					directIntent.putExtra("keepass2android.sftp.reqtype", type); | ||||
| 					directIntent.putExtra("keepass2android.sftp.prompt", text); | ||||
| 					directIntent.setData((Uri.parse("suckit://" + SystemClock.elapsedRealtime()))); | ||||
| 					_appContext.startActivity(directIntent); | ||||
| 				} | ||||
|  | ||||
|  | ||||
|  | ||||
| 				Log.e("KP2AJFS[thread]", "Notifying..."); | ||||
|  | ||||
| 				mNotificationManager.notify(bogon, builder.build()); | ||||
|  | ||||
|  | ||||
|  | ||||
| 				Log.e("KP2AJFS[thread]", "About to go to 'sleep'..."); | ||||
| 				Looper.loop(); | ||||
| 				Log.e("KP2AJFS[thread]", "And we're alive!"); | ||||
|  | ||||
| 				Log.e("KP2AJFS[thread]", "result was: "+(Integer.toString(msg.arg1))); | ||||
|  | ||||
| 				mNotificationManager.cancel(bogon); | ||||
| 			} | ||||
| 		}; | ||||
|  | ||||
| 		t.start(); | ||||
| 		try { | ||||
| 			t.join(); | ||||
| 		} catch (Exception e) { | ||||
| 			return null; | ||||
| 		} | ||||
|  | ||||
| 		if (type.equals("yesno")) | ||||
| 			return new Boolean(msg.arg1 == 1); | ||||
| 		else if (type.equals("message")) | ||||
| 			return null; | ||||
| 		else if (type.equals("password")) { | ||||
| 			if (msg.arg1 == 0) | ||||
| 				return null; | ||||
| 			Bundle b = msg.getData(); | ||||
| 			return b.getString("response"); | ||||
| 		} else | ||||
| 			return null; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	Context _appContext; | ||||
|  | ||||
| 	String _password; | ||||
| 	 | ||||
| 	public SftpUserInfo(String password) { | ||||
| 	public SftpUserInfo(String password, Context appContext) | ||||
| 	{ | ||||
| 		_password = password; | ||||
| 		_appContext = appContext; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| @@ -35,12 +140,15 @@ public class SftpUserInfo implements UserInfo { | ||||
|  | ||||
| 	@Override | ||||
| 	public boolean promptYesNo(String message) { | ||||
| 		return true; //continue all operations without user action | ||||
| 		return (Boolean)dance("yesno", message); | ||||
|  | ||||
| 		//test with https://www.sftp.net/public-online-sftp-servers? | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void showMessage(String message) { | ||||
| 		Log.d("KP2AJ", message); | ||||
| 	public void showMessage(String message) | ||||
| 	{ | ||||
| 		dance("message", message); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,4 @@ | ||||
| <vector android:height="24dp" android:viewportHeight="800.0" | ||||
|     android:viewportWidth="800.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <path android:fillColor="#ffffff" android:fillType="evenOdd" android:pathData="m318.7,232c13.6,0 24.6,10.9 24.6,24.4 0,13.5 -11,24.4 -24.6,24.4 -13.6,0 -24.6,-10.9 -24.6,-24.4 0,-13.5 11,-24.4 24.6,-24.4zM453.5,256.4c0,13.5 11,24.4 24.6,24.4 13.6,0 24.6,-10.9 24.6,-24.4 0,-13.5 -11,-24.4 -24.6,-24.4 -13.6,0 -24.6,10.9 -24.6,24.4zM399.8,177.7M140.2,600.6v47h517.3v-47zM140.2,350.9v47h517.3v-47zM140.1,481.2h191.8c-0.8,-4.1 -1.2,-8.3 -1.2,-12.4 0,-12.4 3.4,-24.2 9.9,-34.6L140.1,434.2ZM657.5,481.2v-47L454.9,434.2c6.5,10.4 9.8,22.2 9.8,34.6 0,4.1 -0.4,8.3 -1.2,12.4zM140.1,517.4v47h186.6l14.3,-47zM454.3,517.4 L468.7,564.4h188.8v-47zM432.7,565.8 L411.7,496.9 414.4,495.3c10.3,-5.9 16.7,-16.9 16.7,-28.6 0,-18.2 -15,-33 -33.3,-33 -18.3,0 -33.3,14.8 -33.3,33 0,11.8 6.4,22.7 16.7,28.6l2.7,1.6 -21.1,68.9zM507.5,158.5 L507.7,158.2 543.3,106.9c2.4,-3.5 1.8,-8.1 -1.4,-10.3 -3.2,-2.2 -7.7,-1.1 -10.2,2.4l-37.2,53.5 -0.1,0.3c-29.3,-11.8 -62.1,-18.5 -96.8,-18.5 -35.2,0 -68.5,6.9 -98.1,19L261.8,99c-2.4,-3.5 -7,-4.6 -10.2,-2.4 -3.2,2.2 -3.8,6.8 -1.4,10.3l36.2,52.2c-66.8,32.2 -111.9,92.4 -111.9,161.3h42.9c0,-79.1 80.8,-143.5 180.1,-143.5 99.3,0 180.1,64.3 180.1,143.5h42.9c0.2,-69.3 -45.4,-129.8 -113,-161.9z"/> | ||||
| </vector> | ||||
| @@ -135,7 +135,12 @@ package com.crocoapps.javafilestoragetest; | ||||
| import group.pals.android.lib.ui.filechooser.FileChooserActivity; | ||||
| import group.pals.android.lib.ui.filechooser.providers.BaseFileProviderUtils; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.io.Reader; | ||||
| import java.io.UnsupportedEncodingException; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| @@ -526,9 +531,9 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag | ||||
| 	} | ||||
|  | ||||
| 	static JavaFileStorage createStorageToTest(Context ctx, Context appContext, boolean simulateRestart) { | ||||
| 		//storageToTest = new SftpStorage(); | ||||
| 		storageToTest = new SftpStorage(ctx.getApplicationContext()); | ||||
| 		//storageToTest = new SkyDriveFileStorage("000000004010C234", appContext); | ||||
| 		storageToTest = new OneDriveStorage(appContext, "000000004010C234"); | ||||
| 		//storageToTest = new OneDriveStorage(appContext, "000000004010C234"); | ||||
| 		//storageToTest = new GoogleDriveFileStorage(); | ||||
| 		/*storageToTest = new WebDavStorage(new ICertificateErrorHandler() { | ||||
| 			@Override | ||||
| @@ -662,6 +667,20 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag | ||||
| 		return this; | ||||
| 	} | ||||
|  | ||||
| 	public static String readStream(InputStream is) { | ||||
| 		StringBuilder sb = new StringBuilder(512); | ||||
| 		try { | ||||
| 			Reader r = new InputStreamReader(is, "UTF-8"); | ||||
| 			int c = 0; | ||||
| 			while ((c = r.read()) != -1) { | ||||
| 				sb.append((char) c); | ||||
| 			} | ||||
| 		} catch (IOException e) { | ||||
| 			throw new RuntimeException(e); | ||||
| 		} | ||||
| 		return sb.toString(); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void performManualFileSelect(boolean isForSave, final int requestCode, | ||||
| 			String protocolId) | ||||
| @@ -669,6 +688,30 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag | ||||
| 		if (protocolId.equals("sftp")) | ||||
| 		{ | ||||
| 			final View view = getLayoutInflater().inflate(R.layout.sftp_credentials, null); | ||||
|  | ||||
| 			view.findViewById(R.id.send_public_key).setOnClickListener(v -> { | ||||
| 				Intent sendIntent = new Intent(); | ||||
|  | ||||
|  | ||||
|                 SftpStorage sftpStorage = (SftpStorage)storageToTest; | ||||
|                 try { | ||||
|                     String pub_filename = sftpStorage.createKeyPair(); | ||||
|  | ||||
|                     sendIntent.setAction(Intent.ACTION_SEND); | ||||
|                     sendIntent.putExtra(Intent.EXTRA_TEXT, readStream(new FileInputStream(pub_filename))); | ||||
|  | ||||
|                     sendIntent.putExtra(Intent.EXTRA_SUBJECT, "Keepass2Android sftp public key"); | ||||
|                     sendIntent.setType("text/plain"); | ||||
|                     this.startActivity(Intent.createChooser(sendIntent, "Send public key to...")); | ||||
|                 } | ||||
|                 catch (Exception ex) | ||||
|                 { | ||||
|                     Toast.makeText(this,"Failed to create key pair: " + ex.getMessage(), Toast.LENGTH_LONG); | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|  | ||||
| 			}); | ||||
| 			new AlertDialog.Builder(this) | ||||
| 					.setView(view) | ||||
| 					.setTitle("Enter SFTP credentials") | ||||
|   | ||||
| @@ -63,6 +63,9 @@ | ||||
|             android:singleLine="true" | ||||
| 			android:text="/home/philipp" | ||||
| 			 /> | ||||
| 		 | ||||
| 		<Button android:id="@+id/send_public_key" | ||||
| 			android:layout_width="fill_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="send public key" /> | ||||
|  | ||||
| </LinearLayout> | ||||
							
								
								
									
										2
									
								
								src/java/KP2ASoftkeyboard_AS/.idea/misc.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								src/java/KP2ASoftkeyboard_AS/.idea/misc.xml
									
									
									
										generated
									
									
									
								
							| @@ -24,7 +24,7 @@ | ||||
|       </value> | ||||
|     </option> | ||||
|   </component> | ||||
|   <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> | ||||
|   <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> | ||||
|     <output url="file://$PROJECT_DIR$/build/classes" /> | ||||
|   </component> | ||||
|   <component name="ProjectType"> | ||||
|   | ||||
| @@ -521,6 +521,7 @@ public class KP2AKeyboard extends InputMethodService | ||||
|             mOrientation = conf.orientation; | ||||
|             reloadKeyboards(); | ||||
|         } | ||||
|         updateKp2aKeyLabels(); | ||||
|         mConfigurationChanging = true; | ||||
|         super.onConfigurationChanged(conf); | ||||
|         mConfigurationChanging = false; | ||||
| @@ -545,6 +546,7 @@ public class KP2AKeyboard extends InputMethodService | ||||
|         	mKeyboardSwitcher.setKeyboardMode( | ||||
|                     KeyboardSwitcher.MODE_TEXT, 0); | ||||
|         } | ||||
|         updateKp2aKeyLabels(); | ||||
|          | ||||
|         return mKeyboardSwitcher.getInputView(); | ||||
|     } | ||||
| @@ -706,6 +708,7 @@ public class KP2AKeyboard extends InputMethodService | ||||
| 	                        attribute.imeOptions); | ||||
| 	        } | ||||
|         } | ||||
|         updateKp2aKeyLabels(); | ||||
| 	} | ||||
|  | ||||
| 	private void updateShowKp2aMode() { | ||||
| @@ -1365,7 +1368,8 @@ public class KP2AKeyboard extends InputMethodService | ||||
| 	} | ||||
|  | ||||
| 	private void onKp2aPasswordKeyPressed() { | ||||
| 		commitStringForTyping(KeyboardData.availableFields.get(KeyboardData.kp2aFieldIndex+1)); | ||||
|         if (KeyboardData.availableFields.size() > KeyboardData.kp2aFieldIndex+1) //some entries may have only title, then there are no two buttons available | ||||
| 		    commitStringForTyping(KeyboardData.availableFields.get(KeyboardData.kp2aFieldIndex+1)); | ||||
| 	} | ||||
|  | ||||
|  | ||||
| @@ -1394,38 +1398,61 @@ public class KP2AKeyboard extends InputMethodService | ||||
|         updateKp2aKeyLabels(); | ||||
|     } | ||||
|  | ||||
|     String makeShort(String input, int lineLength) | ||||
|     { | ||||
|         String result = input; | ||||
|         if (input.length() > lineLength) | ||||
|         { | ||||
|             result = input.substring(0,lineLength-1)+"…"; | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     private void updateKp2aKeyLabels() { | ||||
|         for (Keyboard.Key key : mKeyboardSwitcher.getInputView().getKeyboard().getKeys()) { | ||||
|  | ||||
|             boolean isFirstKey = false; | ||||
|             boolean isSecondKey = false; | ||||
|             for (int code : key.codes) { | ||||
|                 if (code == -201) | ||||
|                     isFirstKey = true; | ||||
|                 if (code == -202) | ||||
|                     isSecondKey = true; | ||||
|             } | ||||
|         if ((mKeyboardSwitcher.getInputView() != null) | ||||
|             && (mKeyboardSwitcher.getInputView().getKeyboard() != null)) | ||||
|         { | ||||
|             for (Keyboard.Key key : mKeyboardSwitcher.getInputView().getKeyboard().getKeys()) { | ||||
|  | ||||
|                 boolean isFirstKey = false; | ||||
|                 boolean isSecondKey = false; | ||||
|                 for (int code : key.codes) { | ||||
|                     if (code == -201) | ||||
|                         isFirstKey = true; | ||||
|                     if (code == -202) | ||||
|                         isSecondKey = true; | ||||
|                 } | ||||
|  | ||||
|  | ||||
|             int fieldIndex = -1; | ||||
|             if (isFirstKey) { | ||||
|                 fieldIndex = KeyboardData.kp2aFieldIndex; | ||||
|             } | ||||
|             if (isSecondKey) | ||||
|             { | ||||
|                 fieldIndex = KeyboardData.kp2aFieldIndex+1; | ||||
|             } | ||||
|             if (fieldIndex >= 0) | ||||
|             { | ||||
|                 String displayName = KeyboardData.availableFields.get(fieldIndex).displayName; | ||||
|                 if ("Password".equals(KeyboardData.availableFields.get(fieldIndex).key)) | ||||
|                     displayName = getString(R.string.kp2a_password); //might be a shorter variant | ||||
|                 if ("UserName".equals(KeyboardData.availableFields.get(fieldIndex).key )) | ||||
|                     displayName = getString(R.string.kp2a_user); //might be a shorter variant | ||||
|                 key.label = displayName; | ||||
|                 int fieldIndex = -1; | ||||
|                 if (isFirstKey) { | ||||
|                     fieldIndex = KeyboardData.kp2aFieldIndex; | ||||
|                 } | ||||
|                 if (isSecondKey) { | ||||
|                     fieldIndex = KeyboardData.kp2aFieldIndex + 1; | ||||
|                 } | ||||
|  | ||||
|                 if (fieldIndex >= 0) { | ||||
|                     key.label = ""; | ||||
|                     if (fieldIndex < KeyboardData.availableFields.size()) { | ||||
|                         String displayName = ""; | ||||
|                         StringForTyping fieldData = KeyboardData.availableFields.get(fieldIndex); | ||||
|                         if (fieldData != null) { | ||||
|                             displayName = makeShort(fieldData.displayName, 10); | ||||
|  | ||||
|                             if ("Password".equals(fieldData.key)) | ||||
|                                 displayName = getString(R.string.kp2a_password); //might be a shorter variant | ||||
|                             if ("UserName".equals(fieldData.key)) | ||||
|                                 displayName = getString(R.string.kp2a_user); //might be a shorter variant | ||||
|                         } | ||||
|                         key.label = displayName; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             mKeyboardSwitcher.getInputView().invalidateAllKeys(); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     private void onKp2aKeyPressed() { | ||||
| @@ -1455,14 +1482,135 @@ public class KP2AKeyboard extends InputMethodService | ||||
|         } | ||||
|     } | ||||
|  | ||||
| 	private void showKp2aDialog() { | ||||
|         final EditorInfo attribute = getCurrentInputEditorInfo(); | ||||
|         final String clientPackageName = attribute.packageName; | ||||
| 	private void showKp2aDialog() | ||||
|     { | ||||
|         boolean androidP = android.os.Build.VERSION.SDK_INT >= 28; | ||||
|         //due to a change in Android P, showing the dialog as dialog does not work (only visible | ||||
|         // above the keyboard, not above the target application). Use an activity here. | ||||
|         // However, this is not perfect as it has another behavior regarding which task is | ||||
|         // in foreground, e.g. Chrome closes the IME when the activity is brought up which causes | ||||
|         // trouble entering data. So we still use the dialog in previous android versions. | ||||
|         if (androidP) | ||||
|         { | ||||
|             final EditorInfo attribute = getCurrentInputEditorInfo(); | ||||
|             final String clientPackageName = attribute.packageName; | ||||
|  | ||||
|             Intent i = new Intent(this, Kp2aDialog.class); | ||||
|             i.putExtra("clientPackageName", clientPackageName); | ||||
|             i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|             startActivity(i); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|  | ||||
|             AlertDialog.Builder builder = new AlertDialog.Builder(this); | ||||
|             String title = "Keepass2Android"; | ||||
|             List<StringForTyping> availableFields = keepass2android.kbbridge.KeyboardData.availableFields; | ||||
|  | ||||
|             final EditorInfo attribute = getCurrentInputEditorInfo(); | ||||
|             attribute.dump(new Printer() { | ||||
|  | ||||
|                 @Override | ||||
|                 public void println(String x) { | ||||
|                     Log.d("KP2AK", x); | ||||
|  | ||||
|                 } | ||||
|             }, ""); | ||||
|             final ArrayList<StringForTyping> items = new ArrayList<StringForTyping>(); | ||||
|             for (StringForTyping entry : availableFields) { | ||||
|                 items.add(entry.clone()); | ||||
|             } | ||||
|  | ||||
|  | ||||
|             StringForTyping openOrChangeEntry = new StringForTyping(); | ||||
|             if (keepass2android.kbbridge.KeyboardData.entryName == null) { | ||||
|                 openOrChangeEntry.displayName = openOrChangeEntry.key = getString(R.string.open_entry); | ||||
|             } else { | ||||
|                 openOrChangeEntry.displayName = openOrChangeEntry.key = getString(R.string.change_entry); | ||||
|             } | ||||
|             openOrChangeEntry.value = "KP2ASPECIAL_SelectEntryTask"; | ||||
|             items.add(openOrChangeEntry); | ||||
|  | ||||
|  | ||||
|             final String clientPackageName = attribute.packageName; | ||||
|  | ||||
|             if ((clientPackageName != null) && (clientPackageName != "")) { | ||||
|                 StringForTyping searchEntry = new StringForTyping(); | ||||
|                 try { | ||||
|                     searchEntry.key = searchEntry.displayName | ||||
|                             = getString(R.string.open_entry_for_app, new Object[]{clientPackageName}); | ||||
|                 } catch (java.util.FormatFlagsConversionMismatchException e) //buggy crowdin support for Arabic? | ||||
|                 { | ||||
|                     android.util.Log.e("KP2A", "Please report this error to crocoapps@gmail.com"); | ||||
|                     android.util.Log.e("KP2A", e.toString()); | ||||
|  | ||||
|                     searchEntry.key = searchEntry.displayName | ||||
|                             = "Search entry for app"; | ||||
|                 } | ||||
|  | ||||
|                 searchEntry.value = "KP2ASPECIAL_SearchUrlTask"; | ||||
|                 items.add(searchEntry); | ||||
|             } | ||||
|  | ||||
|  | ||||
|             builder.setTitle(title); | ||||
|  | ||||
|             CharSequence[] itemNames = new CharSequence[items.size()]; | ||||
|             int i = 0; | ||||
|             for (StringForTyping sft : items) | ||||
|                 itemNames[i++] = sft.displayName; | ||||
|  | ||||
|             builder.setItems(itemNames, | ||||
|                     new DialogInterface.OnClickListener() { | ||||
|                         public void onClick(DialogInterface dialog, int item) { | ||||
|  | ||||
|  | ||||
|                             if (items.get(item).value.startsWith("KP2ASPECIAL")) { | ||||
|                                 //change entry | ||||
|                                 String packageName = getApplicationContext().getPackageName(); | ||||
|                                 Intent startKp2aIntent = getPackageManager().getLaunchIntentForPackage(packageName); | ||||
|                                 if (startKp2aIntent != null) { | ||||
|                                     startKp2aIntent.addCategory(Intent.CATEGORY_LAUNCHER); | ||||
|                                     startKp2aIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); | ||||
|                                     String value = items.get(item).value; | ||||
|                                     String taskName = value.substring("KP2ASPECIAL_".length()); | ||||
|                                     startKp2aIntent.putExtra("KP2A_APPTASK", taskName); | ||||
|                                     if (taskName.equals("SearchUrlTask")) { | ||||
|                                         startKp2aIntent.putExtra("UrlToSearch", "androidapp://" + clientPackageName); | ||||
|                                     } | ||||
|                                     startActivity(startKp2aIntent); | ||||
|                                 } else Log.w("KP2AK", "didn't find intent for " + packageName); | ||||
|                             } else { | ||||
|  | ||||
|                                 StringForTyping theItem = items.get(item); | ||||
|  | ||||
|                                 commitStringForTyping(theItem); | ||||
|  | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
|                     }); | ||||
|  | ||||
|             builder.setNegativeButton(android.R.string.cancel, | ||||
|                     new DialogInterface.OnClickListener() { | ||||
|                         public void onClick(DialogInterface dialog, int id) { | ||||
|                             // User cancelled the dialog | ||||
|                         } | ||||
|                     }); | ||||
|  | ||||
|             // Create the AlertDialog | ||||
|             AlertDialog dialog = builder.create(); | ||||
|             Window window = dialog.getWindow(); | ||||
|             WindowManager.LayoutParams lp = window.getAttributes(); | ||||
|             LatinKeyboardView inputView = mKeyboardSwitcher.getInputView(); | ||||
|             lp.token = inputView.getWindowToken(); | ||||
|             lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; | ||||
|             window.setAttributes(lp); | ||||
|             window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); | ||||
|  | ||||
|             dialog.show(); | ||||
|         } | ||||
|  | ||||
|         Intent i = new Intent(this, Kp2aDialog.class); | ||||
|         i.putExtra("clientPackageName", clientPackageName); | ||||
|         i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|         startActivity(i); | ||||
| 	} | ||||
| 	public void commitStringForTyping(StringForTyping theItem) { | ||||
| 		 | ||||
| @@ -1480,7 +1628,7 @@ public class KP2AKeyboard extends InputMethodService | ||||
| 		 | ||||
| 		 | ||||
| 										 | ||||
| 		Log.d("KP2AK", "committing text for " + theItem.key); | ||||
|  | ||||
| 		commitKp2aString(theItem.value, getCurrentInputEditorInfo()); | ||||
| 	} | ||||
|  | ||||
| @@ -1789,6 +1937,7 @@ public class KP2AKeyboard extends InputMethodService | ||||
|               } | ||||
|               setCandidatesViewShown(true); | ||||
|               updateInputViewShown(); | ||||
|               updateKp2aKeyLabels(); | ||||
|               postUpdateSuggestions(); | ||||
|           } | ||||
|       }); | ||||
|   | ||||
| @@ -30,6 +30,7 @@ using Android.Widget; | ||||
| using Android.Preferences; | ||||
| using Android.Text.Method; | ||||
| using System.Globalization; | ||||
| using System.Net; | ||||
| using Android.Content.PM; | ||||
| using Android.Webkit; | ||||
| using Android.Graphics; | ||||
| @@ -540,9 +541,12 @@ namespace keepass2android | ||||
| 				binaryDirectory = CacheDir.Path + File.Separator + AttachmentContentProvider.AttachmentCacheSubDir; | ||||
|  | ||||
| 			string filepart = key; | ||||
| 			if (writeToCacheDirectory) | ||||
| 				filepart = filepart.Replace(" ", ""); | ||||
| 			var targetFile = new File(binaryDirectory, filepart); | ||||
| 		    if (writeToCacheDirectory) | ||||
| 		    { | ||||
| 		        Java.Lang.String javaFilename = new Java.Lang.String(filepart); | ||||
|                 filepart = javaFilename.ReplaceAll("[^a-zA-Z0-9.-]", "_"); | ||||
|             } | ||||
| 		    var targetFile = new File(binaryDirectory, filepart); | ||||
|  | ||||
| 			File parent = targetFile.ParentFile; | ||||
|  | ||||
| @@ -1022,7 +1026,12 @@ namespace keepass2android | ||||
| 			{ | ||||
| 				case Resource.Id.menu_donate: | ||||
| 					return Util.GotoDonateUrl(this); | ||||
| 				case Resource.Id.menu_toggle_pass: | ||||
|                 case Resource.Id.menu_delete: | ||||
|                     DeleteEntry task = new DeleteEntry(this, App.Kp2a, Entry, | ||||
|                         new ActionOnFinish(this, (success, message, activity) => { if (success) { RequiresRefresh(); Finish();}})); | ||||
|                     task.Start(); | ||||
|                     break; | ||||
|                 case Resource.Id.menu_toggle_pass: | ||||
| 					if (_showPassword) | ||||
| 					{ | ||||
| 						item.SetTitle(Resource.String.show_password); | ||||
|   | ||||
| @@ -279,7 +279,17 @@ namespace keepass2android | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		private void CreateNewFromKpEntryTemplate(Database db, PwEntry templateEntry) | ||||
| 	    protected override void OnStart() | ||||
| 	    { | ||||
| 	        base.OnStart(); | ||||
| 	        if (PreferenceManager.GetDefaultSharedPreferences(this) | ||||
| 	            .GetBoolean(GetString(Resource.String.UseKp2aKeyboardInKp2a_key), false)) | ||||
| 	        { | ||||
| 	            CopyToClipboardService.ActivateKeyboard(this); | ||||
| 	        } | ||||
|         } | ||||
|  | ||||
| 	    private void CreateNewFromKpEntryTemplate(Database db, PwEntry templateEntry) | ||||
| 		{ | ||||
| 			var entry = new PwEntry(true, true); | ||||
| 			KpEntryTemplatedEdit.InitializeEntry(entry, templateEntry); | ||||
|   | ||||
| @@ -42,15 +42,49 @@ namespace keepass2android | ||||
| 			AlertDialog.Builder builder = new AlertDialog.Builder(activity); | ||||
| 			View dlgContents = activity.LayoutInflater.Inflate(Resource.Layout.sftpcredentials, null); | ||||
|  | ||||
| 		    if (!defaultPath.EndsWith(_schemeSeparator)) | ||||
| 		    var spinner = dlgContents.FindViewById<Spinner>(Resource.Id.sftp_auth_mode_spinner); | ||||
| 		    dlgContents.FindViewById<Button>(Resource.Id.send_public_key_button).Click += (sender, args) => | ||||
| 		    { | ||||
| 		        var fileStorage = new Keepass2android.Javafilestorage.SftpStorage(); | ||||
| 		        var fileStorage = new Keepass2android.Javafilestorage.SftpStorage(activity.ApplicationContext); | ||||
| 		        string pub_filename = fileStorage.CreateKeyPair(); | ||||
|  | ||||
| 		        Intent sendIntent = new Intent(); | ||||
|                 sendIntent.SetAction(Intent.ActionSend); | ||||
| 		        sendIntent.PutExtra(Intent.ExtraText, System.IO.File.ReadAllText(pub_filename)); | ||||
|  | ||||
| 		        sendIntent.PutExtra(Intent.ExtraSubject, "Keepass2Android sftp public key"); | ||||
| 		        sendIntent.SetType("text/plain"); | ||||
| 		        activity.StartActivity(Intent.CreateChooser(sendIntent, "Send public key to...")); | ||||
|             }; | ||||
|  | ||||
|  | ||||
|             spinner.ItemSelected += (sender, args) => | ||||
| 		    { | ||||
| 		        if (spinner.SelectedItemPosition == 0) | ||||
| 		        { | ||||
| 		            dlgContents.FindViewById<EditText>(Resource.Id.sftp_password).Visibility = ViewStates.Visible; | ||||
| 		            dlgContents.FindViewById<Button>(Resource.Id.send_public_key_button).Visibility = ViewStates.Gone; | ||||
|                 } | ||||
| 		        else | ||||
| 		        { | ||||
| 		            dlgContents.FindViewById<EditText>(Resource.Id.sftp_password).Visibility = ViewStates.Gone; | ||||
| 		            dlgContents.FindViewById<Button>(Resource.Id.send_public_key_button).Visibility = ViewStates.Visible; | ||||
|                 } | ||||
| 		    }; | ||||
|  | ||||
|             if (!defaultPath.EndsWith(_schemeSeparator)) | ||||
| 		    { | ||||
| 		        var fileStorage = new Keepass2android.Javafilestorage.SftpStorage(activity.ApplicationContext); | ||||
|                 SftpStorage.ConnectionInfo ci = fileStorage.SplitStringToConnectionInfo(defaultPath); | ||||
| 		        dlgContents.FindViewById<EditText>(Resource.Id.sftp_host).Text = ci.Host; | ||||
| 		        dlgContents.FindViewById<EditText>(Resource.Id.sftp_port).Text = ci.Port.ToString(); | ||||
| 		        dlgContents.FindViewById<EditText>(Resource.Id.sftp_user).Text = ci.Username; | ||||
| 		        dlgContents.FindViewById<EditText>(Resource.Id.sftp_password).Text = ci.Password; | ||||
| 		        dlgContents.FindViewById<EditText>(Resource.Id.sftp_initial_dir).Text = ci.LocalPath; | ||||
| 		        if (string.IsNullOrEmpty(ci.Password)) | ||||
| 		        { | ||||
| 		            spinner.SetSelection(1); | ||||
| 		        } | ||||
|             } | ||||
|  | ||||
| 			builder.SetView(dlgContents); | ||||
| @@ -67,7 +101,7 @@ namespace keepass2android | ||||
| 										  string initialPath = dlgContents.FindViewById<EditText>(Resource.Id.sftp_initial_dir).Text; | ||||
| 									      if (string.IsNullOrEmpty(initialPath)) | ||||
| 									          initialPath = "/"; | ||||
|                                           string sftpPath = new Keepass2android.Javafilestorage.SftpStorage().BuildFullPath(host, port, initialPath, user, | ||||
|                                           string sftpPath = new Keepass2android.Javafilestorage.SftpStorage(activity.ApplicationContext).BuildFullPath(host, port, initialPath, user, | ||||
| 																										  password); | ||||
| 										  onStartBrowse(sftpPath); | ||||
| 									  }); | ||||
|   | ||||
| @@ -19,7 +19,7 @@ using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| using System.Security.Cryptography; | ||||
| using System.Net; | ||||
| using System.Threading.Tasks; | ||||
| using System.Xml; | ||||
| using System.Xml.Serialization; | ||||
| @@ -38,16 +38,12 @@ using Android.Preferences; | ||||
| using Android.Text; | ||||
| using Android.Content.PM; | ||||
| using Android.Graphics; | ||||
| using Android.Hardware.Fingerprints; | ||||
| using Android.Provider; | ||||
| using Android.Support.Design.Widget; | ||||
| using Android.Support.V4.Widget; | ||||
| using Android.Support.V7.App; | ||||
| using Java.Lang; | ||||
| using keepass2android; | ||||
| using KeePassLib.Keys; | ||||
| using KeePassLib.Serialization; | ||||
| using KeePassLib.Utility; | ||||
| using Keepass2android.Pluginsdk; | ||||
| using OtpKeyProv; | ||||
| using keepass2android.Io; | ||||
| @@ -60,12 +56,10 @@ using Object = Java.Lang.Object; | ||||
| using Process = Android.OS.Process; | ||||
|  | ||||
| using KeeChallenge; | ||||
| using KeePassLib.Cryptography.KeyDerivation; | ||||
| using AlertDialog = Android.App.AlertDialog; | ||||
| using Enum = System.Enum; | ||||
| using Exception = System.Exception; | ||||
| using String = System.String; | ||||
| using Toolbar = Android.Support.V7.Widget.Toolbar; | ||||
|  | ||||
| namespace keepass2android | ||||
| { | ||||
| @@ -80,15 +74,13 @@ namespace keepass2android | ||||
|  | ||||
| 		enum KeyProviders | ||||
| 		{ | ||||
| 			//int values correspond to indices in passwordSpinner | ||||
| 			None = 0, | ||||
| 			KeyFile = 1, | ||||
| 			Otp = 2, | ||||
| 			OtpRecovery = 3, | ||||
| 			Challenge = 4, | ||||
| 			ChalRecovery = 5, | ||||
| 			ChallengeXC = 6 //KeepassXC compatible Challenge-Response | ||||
| 		} | ||||
| 			ChallengeXC = 6, //KeepassXC compatible Challenge-Response | ||||
|         } | ||||
|  | ||||
| 		public const String KeyDefaultFilename = "defaultFileName"; | ||||
|  | ||||
| @@ -106,9 +98,9 @@ namespace keepass2android | ||||
| 		private const string KeyProviderIdChallenge = "KP2A-Chal"; | ||||
| 		private const string KeyProviderIdChallengeRecovery = "KP2A-ChalSecret"; | ||||
| 		private const string KeyProviderIdChallengeXC = "KP2A-ChalXC"; | ||||
| 		 | ||||
|  | ||||
| 		private const int RequestCodePrepareDbFile = 1000; | ||||
|  | ||||
|         private const int RequestCodePrepareDbFile = 1000; | ||||
| 		private const int RequestCodePrepareOtpAuxFile = 1001; | ||||
|          | ||||
| 		private const int RequestCodeSelectKeyfile = 1003; | ||||
| @@ -120,7 +112,7 @@ namespace keepass2android | ||||
| 		private bool _loadDbTaskOffline; //indicate if preloading was started with offline mode | ||||
|  | ||||
| 		private IOConnectionInfo _ioConnection; | ||||
| 		private String _keyFileOrProvider; | ||||
| 		private String _keyFile; | ||||
| 		bool _showPassword; | ||||
|  | ||||
| 		internal AppTask AppTask; | ||||
| @@ -130,27 +122,8 @@ namespace keepass2android | ||||
| 		private List<String> _pendingOtps = new List<string>(); | ||||
|  | ||||
|  | ||||
|  | ||||
| 		KeyProviders KeyProviderType | ||||
| 		{ | ||||
| 			get | ||||
| 			{ | ||||
| 				if (_keyFileOrProvider == null) | ||||
| 					return KeyProviders.None; | ||||
| 				if (_keyFileOrProvider == KeyProviderIdOtp) | ||||
| 					return KeyProviders.Otp; | ||||
| 				if (_keyFileOrProvider == KeyProviderIdOtpRecovery) | ||||
| 					return KeyProviders.OtpRecovery; | ||||
| 				if (_keyFileOrProvider == KeyProviderIdChallenge) | ||||
| 					return KeyProviders.Challenge; | ||||
| 				if (_keyFileOrProvider == KeyProviderIdChallengeRecovery) | ||||
| 					return KeyProviders.ChalRecovery; | ||||
| 				if (_keyFileOrProvider == KeyProviderIdChallengeXC) | ||||
| 					return KeyProviders.ChallengeXC; | ||||
| 				return KeyProviders.KeyFile; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 	    private HashSet<KeyProviders> KeyProviderTypes = new HashSet<KeyProviders>(); | ||||
| 		 | ||||
| 		private bool _rememberKeyfile; | ||||
| 		ISharedPreferences _prefs; | ||||
|  | ||||
| @@ -253,7 +226,6 @@ namespace keepass2android | ||||
|  | ||||
| 			AppTask.TryGetFromActivityResult(data, ref AppTask); | ||||
|  | ||||
| 			//NOTE: original code from k eepassdroid used switch ((Android.App.Result)requestCode) { (but doesn't work here, although k eepassdroid works) | ||||
| 			switch(resultCode) { | ||||
|  | ||||
| 				case KeePass.ExitNormal: // Returned to this screen using the Back key | ||||
| @@ -271,13 +243,13 @@ namespace keepass2android | ||||
| 					// The database has already been locked, and the quick unlock screen will be shown if appropriate | ||||
|  | ||||
| 					_rememberKeyfile = _prefs.GetBoolean(GetString(Resource.String.keyfile_key), Resources.GetBoolean(Resource.Boolean.keyfile_default)); //update value | ||||
| 					if ((KeyProviderType == KeyProviders.KeyFile) && (_rememberKeyfile)) | ||||
| 					if (KeyProviderHasKeyFile() && (_rememberKeyfile)) | ||||
| 					{ | ||||
| 						//check if the keyfile was changed (by importing to internal directory) | ||||
| 						var newKeyFile = GetKeyFile(_ioConnection.Path); | ||||
| 						if (newKeyFile != _keyFileOrProvider) | ||||
| 						var newKeyProviderString = LoadKeyProviderStringForIoc(_ioConnection.Path); | ||||
| 						if (newKeyProviderString != GetKeyProviderString()) | ||||
| 						{ | ||||
| 							_keyFileOrProvider = newKeyFile; | ||||
| 							SetKeyProviderFromString(newKeyProviderString); | ||||
| 							UpdateKeyfileIocView(); | ||||
| 						} | ||||
| 					} | ||||
| @@ -310,7 +282,7 @@ namespace keepass2android | ||||
| 						Handler handler = new Handler(); | ||||
| 						OnFinish onFinish = new AfterLoad(handler, this, _ioConnection); | ||||
| 						_performingLoad = true; | ||||
| 						LoadDb task = new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, _keyFileOrProvider, onFinish); | ||||
| 						LoadDb task = new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, GetKeyProviderString(), onFinish); | ||||
| 						_loadDbFileTask = null; // prevent accidental re-use | ||||
| 						new ProgressTask(App.Kp2a, this, task).Run(); | ||||
| 					} | ||||
| @@ -321,20 +293,20 @@ namespace keepass2android | ||||
| 					{ | ||||
| 						IOConnectionInfo ioc = new IOConnectionInfo(); | ||||
| 						SetIoConnectionFromIntent(ioc, data); | ||||
| 						_keyFileOrProvider = IOConnectionInfo.SerializeToString(ioc); | ||||
| 						_keyFile = IOConnectionInfo.SerializeToString(ioc); | ||||
| 						UpdateKeyfileIocView(); | ||||
| 					} | ||||
| 					break; | ||||
| 				case (Result)FileStorageResults.FileUsagePrepared: | ||||
| 					if (requestCode == RequestCodePrepareDbFile) | ||||
| 					{ | ||||
| 						if (KeyProviderType == KeyProviders.KeyFile) | ||||
| 						if (KeyProviderTypes.Contains(KeyProviders.KeyFile)) | ||||
| 						{ | ||||
| 							 | ||||
|                             //if the user has not yet selected a keyfile, _keyFileOrProvider is empty  | ||||
| 							if (string.IsNullOrEmpty(_keyFileOrProvider) == false) | ||||
|  | ||||
|                             //if the user has not yet selected a keyfile, _keyFile is empty  | ||||
|                             if (string.IsNullOrEmpty(_keyFile) == false) | ||||
| 							{ | ||||
| 								var iocKeyfile = IOConnectionInfo.UnserializeFromString(_keyFileOrProvider); | ||||
| 								var iocKeyfile = IOConnectionInfo.UnserializeFromString(_keyFile); | ||||
|  | ||||
| 								App.Kp2a.GetFileStorage(iocKeyfile) | ||||
| 									.PrepareFileUsage(new FileStorageSetupInitiatorActivity(this, OnActivityResult, null), iocKeyfile, | ||||
| @@ -428,16 +400,17 @@ namespace keepass2android | ||||
| 		            else | ||||
| 		            { | ||||
| 		                Toast.MakeText(this, Resource.String.bad_resp, ToastLength.Long).Show(); | ||||
| 		                return; | ||||
| 		            } | ||||
| 		        } | ||||
| 		    } | ||||
| 		} | ||||
|  | ||||
| 		private AuxFileLoader GetAuxFileLoader() | ||||
| 	     | ||||
|  | ||||
| 	    private AuxFileLoader GetAuxFileLoader() | ||||
| 		{ | ||||
| 			if (_keyFileOrProvider == KeyProviderIdChallenge) | ||||
| 			{ | ||||
| 		    if (KeyProviderTypes.Contains(KeyProviders.Challenge)) | ||||
|             { | ||||
| 				return new ChallengeAuxFileLoader(this); | ||||
| 			} | ||||
| 			else | ||||
| @@ -448,8 +421,8 @@ namespace keepass2android | ||||
| 		private void UpdateKeyfileIocView() | ||||
| 		{ | ||||
| 			//store keyfile in the view so that we can show the selected keyfile again if the user switches to another key provider and back to key file | ||||
| 			FindViewById<TextView>(Resource.Id.label_keyfilename).Tag = _keyFileOrProvider; | ||||
| 			if (string.IsNullOrEmpty(_keyFileOrProvider)) | ||||
| 			FindViewById<TextView>(Resource.Id.label_keyfilename).Tag = _keyFile; | ||||
| 			if (string.IsNullOrEmpty(_keyFile)) | ||||
| 			{ | ||||
| 				FindViewById<TextView>(Resource.Id.filestorage_label).Visibility = ViewStates.Gone; | ||||
| 				FindViewById<ImageView>(Resource.Id.filestorage_logo).Visibility = ViewStates.Gone; | ||||
| @@ -457,7 +430,7 @@ namespace keepass2android | ||||
| 			 | ||||
| 				return; | ||||
| 			} | ||||
| 			var ioc = IOConnectionInfo.UnserializeFromString(_keyFileOrProvider); | ||||
| 			var ioc = IOConnectionInfo.UnserializeFromString(_keyFile); | ||||
| 			string displayPath = App.Kp2a.GetFileStorage(ioc).GetDisplayName(ioc); | ||||
| 			int protocolSeparatorPos = displayPath.IndexOf("://", StringComparison.Ordinal); | ||||
| 			string protocolId = protocolSeparatorPos < 0 ? | ||||
| @@ -531,7 +504,7 @@ namespace keepass2android | ||||
| 										intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, true); | ||||
| 										intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, false); | ||||
| 										intent.PutExtra(FileStorageSetupDefs.ExtraIsForSave, false); | ||||
| 										intent.PutExtra(SelectStorageLocationActivity.ExtraKeyWritableRequirements, (int)SelectStorageLocationActivity.WritableRequirements.WriteDemanded); | ||||
| 										intent.PutExtra(SelectStorageLocationActivity.ExtraKeyWritableRequirements, (int)SelectStorageLocationActivityBase.WritableRequirements.WriteDemanded); | ||||
| 										Activity.StartActivityForResult(intent, RequestCodeSelectAuxFile); | ||||
| 									} | ||||
| 									else | ||||
| @@ -586,16 +559,7 @@ namespace keepass2android | ||||
| 				IOConnectionInfo iocAux = fileStorage.GetFilePath(parentPath, filename); | ||||
| 				return iocAux; | ||||
| 			} | ||||
|  | ||||
| 		 | ||||
|  | ||||
| 			private static IOConnectionInfo GetAuxFileIoc(KeyProviderQueryContext ctx) | ||||
| 			{ | ||||
| 				IOConnectionInfo ioc = ctx.DatabaseIOInfo.CloneDeep(); | ||||
| 				var iocAux = GetAuxFileIoc(ioc); | ||||
|  | ||||
| 				return iocAux; | ||||
| 			} | ||||
|              | ||||
|  | ||||
| 			protected override void HandleSuccess() | ||||
| 			{ | ||||
| @@ -700,9 +664,7 @@ namespace keepass2android | ||||
|  | ||||
| 		int count = 1; | ||||
|  | ||||
| 		private DrawerLayout mDrawerLayout; | ||||
| 		//private RecyclerView mDrawerList; | ||||
| 		 | ||||
| 	     | ||||
| 		private string mDrawerTitle; | ||||
| 		private MeasuringRelativeLayout.MeasureArgs _measureArgs; | ||||
| 		private ActivityDesign _activityDesign; | ||||
| @@ -716,7 +678,7 @@ namespace keepass2android | ||||
| 		{ | ||||
| 			PasswordActivity owner; | ||||
|  | ||||
| 			public MyActionBarDrawerToggle(PasswordActivity activity, DrawerLayout layout, int imgRes, int openRes, int closeRes) | ||||
| 			public MyActionBarDrawerToggle(PasswordActivity activity, DrawerLayout layout, int openRes, int closeRes) | ||||
| 				: base(activity, layout, openRes, closeRes) | ||||
| 			{ | ||||
| 				owner = activity; | ||||
| @@ -822,19 +784,22 @@ namespace keepass2android | ||||
| 				if (keyFileFromIntent != null) | ||||
| 				{ | ||||
| 					Kp2aLog.Log("try get keyfile from intent"); | ||||
| 					_keyFileOrProvider = IOConnectionInfo.SerializeToString(IOConnectionInfo.FromPath(keyFileFromIntent)); | ||||
| 				    _keyFile = IOConnectionInfo.SerializeToString(IOConnectionInfo.FromPath(keyFileFromIntent)); | ||||
|                     KeyProviderTypes.Clear(); | ||||
| 				    KeyProviderTypes.Add(KeyProviders.KeyFile); | ||||
| 					Kp2aLog.Log("try get keyfile from intent ok"); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					_keyFileOrProvider = null; | ||||
| 				} | ||||
| 					_keyFile = null; | ||||
| 				    KeyProviderTypes.Clear(); | ||||
|                 } | ||||
| 				_password = i.GetStringExtra(KeyPassword) ?? ""; | ||||
| 				if (string.IsNullOrEmpty(_keyFileOrProvider)) | ||||
| 				if (!KeyProviderTypes.Any()) | ||||
| 				{ | ||||
| 					_keyFileOrProvider = GetKeyFile(_ioConnection.Path); | ||||
|                     SetKeyProviderFromString(LoadKeyProviderStringForIoc(_ioConnection.Path)); | ||||
| 				} | ||||
| 				if ((!string.IsNullOrEmpty(_keyFileOrProvider)) || (_password != "")) | ||||
| 				if ((!string.IsNullOrEmpty(_keyFile)) || (_password != "")) | ||||
| 				{ | ||||
| 					_keepPasswordInOnResume = true; | ||||
| 				} | ||||
| @@ -853,7 +818,7 @@ namespace keepass2android | ||||
|  | ||||
| 			InitializeFilenameView(); | ||||
|  | ||||
| 			if (KeyProviderType == KeyProviders.KeyFile) | ||||
| 			if (KeyProviderTypes.Contains(KeyProviders.KeyFile)) | ||||
| 			{ | ||||
| 				UpdateKeyfileIocView(); | ||||
| 			} | ||||
| @@ -905,8 +870,8 @@ namespace keepass2android | ||||
| 			} | ||||
|  | ||||
|  | ||||
| 			mDrawerTitle = this.Title; | ||||
| 			mDrawerLayout = FindViewById<DrawerLayout>(Resource.Id.drawer_layout); | ||||
| 			mDrawerTitle = Title; | ||||
| 			FindViewById<DrawerLayout>(Resource.Id.drawer_layout); | ||||
| 			var rootview = FindViewById<MeasuringRelativeLayout>(Resource.Id.relative_layout); | ||||
| 			rootview.ViewTreeObserver.GlobalLayout += (sender, args2) => | ||||
| 			{ | ||||
| @@ -924,16 +889,116 @@ namespace keepass2android | ||||
| 			rootview.MeasureEvent += (sender, args) => | ||||
| 			{ | ||||
| 				//Snackbar.Make(rootview, "height="+args.ActualHeight, Snackbar.LengthLong).Show(); | ||||
| 				this._measureArgs = args; | ||||
| 				_measureArgs = args; | ||||
| 			}; | ||||
|  | ||||
| 			if ((int)Build.VERSION.SdkInt >= 23) | ||||
| 				RequestPermissions(new[] { Manifest.Permission.UseFingerprint }, FingerprintPermissionRequestCode); | ||||
| 			 | ||||
| 		} | ||||
| 		const int FingerprintPermissionRequestCode = 99; | ||||
|  | ||||
| 		public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) | ||||
| 	    private const string Kp2aKeyProviderStringPrefix = "_KP2A_KEYTYPES:"; | ||||
|  | ||||
|         private string GetKeyProviderString() | ||||
| 	    { | ||||
| 	        if (!KeyProviderTypes.Any()) | ||||
| 	            return null; | ||||
| 	        string result = Kp2aKeyProviderStringPrefix; | ||||
| 	        foreach (KeyProviders type in KeyProviderTypes) | ||||
| 	        { | ||||
| 	            result += type.ToString(); | ||||
|  | ||||
|                 if (type == KeyProviders.KeyFile) | ||||
| 	            { | ||||
| 	                result += WebUtility.UrlEncode(_keyFile) + ";"; | ||||
| 	            } | ||||
| 	        } | ||||
| 	        return result; | ||||
| 	    } | ||||
|  | ||||
|         private void SetKeyProviderFromString(string keyProviderString) | ||||
| 	    { | ||||
| 	        KeyProviderTypes.Clear(); | ||||
|             if (string.IsNullOrEmpty(keyProviderString)) | ||||
|             { | ||||
|                 _keyFile = null; | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
| 	        if (keyProviderString.StartsWith(Kp2aKeyProviderStringPrefix)) | ||||
| 	        { | ||||
| 	            keyProviderString = keyProviderString.Substring(Kp2aKeyProviderStringPrefix.Length); | ||||
| 	            foreach (string type in keyProviderString.Split(';')) | ||||
| 	            { | ||||
| 	                if (!type.Trim().Any()) | ||||
| 	                    continue; | ||||
| 	                if (type.StartsWith(KeyProviders.KeyFile.ToString())) | ||||
| 	                { | ||||
| 	                    _keyFile = WebUtility.UrlDecode(type.Substring(KeyProviders.KeyFile.ToString().Length)); | ||||
| 	                    KeyProviderTypes.Add(KeyProviders.KeyFile); | ||||
| 	                    continue; | ||||
| 	                } | ||||
| 	                foreach (KeyProviders providerType in Enum.GetValues(typeof(KeyProviders))) | ||||
| 	                { | ||||
| 	                    if (type == providerType.ToString()) | ||||
| 	                    { | ||||
| 	                        KeyProviderTypes.Add(providerType); | ||||
| 	                        break; | ||||
| 	                    } | ||||
| 	                } | ||||
| 	            } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|  | ||||
|                 //legacy mode | ||||
|                 _keyFile = null; | ||||
|                  | ||||
|                 if (keyProviderString == KeyProviderIdOtp) | ||||
|                     KeyProviderTypes.Add(KeyProviders.Otp); | ||||
|                 else if (keyProviderString == KeyProviderIdOtpRecovery) | ||||
|                     KeyProviderTypes.Add(KeyProviders.OtpRecovery); | ||||
|                 else if (keyProviderString == KeyProviderIdChallenge) | ||||
|                     KeyProviderTypes.Add(KeyProviders.Challenge); | ||||
|                 else if (keyProviderString == KeyProviderIdChallengeRecovery) | ||||
|                     KeyProviderTypes.Add(KeyProviders.ChalRecovery); | ||||
|                 else if (keyProviderString == KeyProviderIdChallengeXC) | ||||
|                     KeyProviderTypes.Add(KeyProviders.ChallengeXC); | ||||
|                 else | ||||
|                 { | ||||
|                     KeyProviderTypes.Add(KeyProviders.KeyFile); | ||||
|                     _keyFile = keyProviderString; | ||||
|                 } | ||||
|                  | ||||
|  | ||||
|  | ||||
|                 if (KeyProviderTypes.Contains(KeyProviders.KeyFile)) | ||||
|                 { | ||||
|                     //test if the filename is properly encoded.  | ||||
|                     try | ||||
|                     { | ||||
|                         Kp2aLog.Log("test if stored filename is ok"); | ||||
|                         IOConnectionInfo.UnserializeFromString(_keyFile); | ||||
|                         Kp2aLog.Log("...ok"); | ||||
|                     } | ||||
|                     catch (Exception e) | ||||
|                     { | ||||
|                         //it's not. This is probably because we're upgrading from app version <= 45 | ||||
|                         //where the keyfile was stored plain text and not serialized | ||||
|                         Kp2aLog.Log("no, it's not: " + e.GetType().Name); | ||||
|                         var serializedKeyFile = IOConnectionInfo.SerializeToString(IOConnectionInfo.FromPath(_keyFile)); | ||||
|                         Kp2aLog.Log("now it is!"); | ||||
|                         _keyFile = serializedKeyFile; | ||||
|  | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
| 	    const int FingerprintPermissionRequestCode = 99; | ||||
| 	     | ||||
|  | ||||
| 	    public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) | ||||
| 		{ | ||||
| 			if ((requestCode == FingerprintPermissionRequestCode) && (grantResults.Length > 0) && (grantResults[0] == Permission.Granted)) | ||||
| 			{ | ||||
| @@ -982,9 +1047,10 @@ namespace keepass2android | ||||
| 			{ | ||||
| 				var masterPassword = _fingerprintDec.DecryptStored(Database.GetFingerprintPrefKey(_ioConnection)); | ||||
| 				_password = FindViewById<EditText>(Resource.Id.password_edit).Text = masterPassword; | ||||
| 			    FindViewById<EditText>(Resource.Id.password_edit).Enabled = false; //prevent accidental modification of password | ||||
|  | ||||
| 			} | ||||
| 			catch (Java.Security.GeneralSecurityException ex) | ||||
|             } | ||||
| 			catch (Java.Security.GeneralSecurityException) | ||||
| 			{ | ||||
| 				HandleFingerprintKeyInvalidated(); | ||||
| 				return; | ||||
| @@ -992,8 +1058,9 @@ namespace keepass2android | ||||
| 			 | ||||
| 			btn.PostDelayed(() => | ||||
| 			{ | ||||
| 				//fire | ||||
| 				OnOk(true);	 | ||||
|                 //fire | ||||
|                 OnOk(true); | ||||
| 			    FindViewById<EditText>(Resource.Id.password_edit).Enabled = true; | ||||
| 			}, 500); | ||||
|  | ||||
|         } | ||||
| @@ -1011,7 +1078,7 @@ namespace keepass2android | ||||
| 	        }; | ||||
| 			FindViewById(Resource.Id.btn_nav_donate).Visibility = | ||||
| 				PreferenceManager.GetDefaultSharedPreferences(this) | ||||
| 					.GetBoolean(this.GetString(Resource.String.NoDonateOption_key), false) | ||||
| 					.GetBoolean(GetString(Resource.String.NoDonateOption_key), false) | ||||
| 					? ViewStates.Gone | ||||
| 					: ViewStates.Visible; | ||||
| 	        FindViewById(Resource.Id.btn_nav_about).Click += (sender, args) => | ||||
| @@ -1059,7 +1126,7 @@ namespace keepass2android | ||||
|                 Resource.String.menu_close); | ||||
|              | ||||
|  | ||||
|             _drawerLayout.SetDrawerListener(mDrawerToggle); | ||||
|             _drawerLayout?.SetDrawerListener(mDrawerToggle); | ||||
|  | ||||
| 	        	         | ||||
|             SupportActionBar.SetDisplayHomeAsUpEnabled(true); | ||||
| @@ -1126,9 +1193,10 @@ namespace keepass2android | ||||
| 			} | ||||
|  | ||||
| 			//assume user wants to use OTP (for static password, they need to open KP2A first and select the key provider type, then see OnNewIntent) | ||||
| 			_keyFileOrProvider = KeyProviderIdOtp; | ||||
| 		    KeyProviderTypes.Clear(); | ||||
| 		    KeyProviderTypes.Add(KeyProviders.Otp); | ||||
|  | ||||
| 			if (savedInstanceState == null) //only when not re-creating | ||||
|             if (savedInstanceState == null) //only when not re-creating | ||||
| 			{ | ||||
| 				//remember the OTP for later use | ||||
| 				_pendingOtps.Add(i.GetStringExtra(Intents.OtpExtraKey)); | ||||
| @@ -1178,7 +1246,7 @@ namespace keepass2android | ||||
| 			} | ||||
|  | ||||
| 			 | ||||
| 			_keyFileOrProvider = GetKeyFile(_ioConnection.Path); | ||||
| 			SetKeyProviderFromString(LoadKeyProviderStringForIoc(_ioConnection.Path)); | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| @@ -1241,33 +1309,58 @@ namespace keepass2android | ||||
| 			if (passwordModeSpinner != null) | ||||
| 			{ | ||||
| 				UpdateKeyProviderUiState(); | ||||
| 				passwordModeSpinner.SetSelection((int) KeyProviderType); | ||||
|  | ||||
| 			    int spinnerPos = 0; | ||||
| 			    if (KeyProviderTypes.Contains(KeyProviders.KeyFile)) | ||||
| 			    { | ||||
| 			        if (KeyProviderTypes.Contains(KeyProviders.ChallengeXC)) | ||||
| 			            spinnerPos = 7; | ||||
| 			        else spinnerPos = 1; | ||||
| 			    } | ||||
|                 else if (KeyProviderTypes.Contains(KeyProviders.Otp)) | ||||
| 			        spinnerPos = 2; | ||||
| 			    else if (KeyProviderTypes.Contains(KeyProviders.OtpRecovery)) | ||||
| 			        spinnerPos = 3; | ||||
| 			    else if (KeyProviderTypes.Contains(KeyProviders.Challenge)) | ||||
| 			        spinnerPos = 4; | ||||
| 			    else if (KeyProviderTypes.Contains(KeyProviders.ChalRecovery)) | ||||
| 			        spinnerPos = 5; | ||||
| 			    else if (KeyProviderTypes.Contains(KeyProviders.ChallengeXC)) | ||||
| 			        spinnerPos = 6; | ||||
|  | ||||
|                 passwordModeSpinner.SetSelection(spinnerPos); | ||||
| 				passwordModeSpinner.ItemSelected += (sender, args) => | ||||
| 					{ | ||||
| 				{ | ||||
| 				    KeyProviderTypes.Clear(); | ||||
| 				    _keyFile = null; | ||||
| 						switch (args.Position) | ||||
| 						{ | ||||
| 							case 0: | ||||
| 								_keyFileOrProvider = null; | ||||
| 								break; | ||||
| 							case 1: | ||||
| 								//don't set to "" to prevent losing the filename. (ItemSelected is also called during recreation!) | ||||
| 								_keyFileOrProvider = (FindViewById(Resource.Id.label_keyfilename).Tag ?? "").ToString(); | ||||
|                             //don't set to "" to prevent losing the filename. (ItemSelected is also called during recreation!) | ||||
| 							    _keyFile = (FindViewById(Resource.Id.label_keyfilename).Tag ?? "").ToString(); | ||||
| 							    KeyProviderTypes.Add(KeyProviders.KeyFile); | ||||
| 								break; | ||||
| 							case 2: | ||||
| 								_keyFileOrProvider = KeyProviderIdOtp; | ||||
| 								break; | ||||
| 							    KeyProviderTypes.Add(KeyProviders.Otp); | ||||
|                             break; | ||||
| 							case 3: | ||||
| 								_keyFileOrProvider = KeyProviderIdOtpRecovery; | ||||
| 								break; | ||||
| 							    KeyProviderTypes.Add(KeyProviders.OtpRecovery); | ||||
|                             break; | ||||
| 							case 4: | ||||
| 								_keyFileOrProvider = KeyProviderIdChallenge; | ||||
| 								break; | ||||
| 							    KeyProviderTypes.Add(KeyProviders.Challenge); | ||||
|                             break; | ||||
| 							case 5: | ||||
| 								_keyFileOrProvider = KeyProviderIdChallengeRecovery; | ||||
| 								break; | ||||
| 							    KeyProviderTypes.Add(KeyProviders.ChalRecovery); | ||||
|                             break; | ||||
| 							case 6: | ||||
| 								_keyFileOrProvider = KeyProviderIdChallengeXC; | ||||
| 								break; | ||||
| 							    KeyProviderTypes.Add(KeyProviders.ChallengeXC); | ||||
| 							    break; | ||||
| 						    case 7: | ||||
| 						        KeyProviderTypes.Add(KeyProviders.ChallengeXC); | ||||
| 						        KeyProviderTypes.Add(KeyProviders.KeyFile); | ||||
|                             break; | ||||
| 							default: | ||||
| 								throw new Exception("Unexpected position " + args.Position + " / " + | ||||
| 								                    ((ICursor) ((AdapterView) sender).GetItemAtPosition(args.Position)).GetString(1)); | ||||
| @@ -1291,7 +1384,7 @@ namespace keepass2android | ||||
| 				_showPassword = savedInstanceState.GetBoolean(ShowpasswordKey, false); | ||||
| 				MakePasswordMaskedOrVisible(); | ||||
|  | ||||
| 				_keyFileOrProvider = savedInstanceState.GetString(KeyFileOrProviderKey); | ||||
|                 SetKeyProviderFromString(savedInstanceState.GetString(KeyFileOrProviderKey)); | ||||
| 				_password = FindViewById<EditText>(Resource.Id.password_edit).Text = savedInstanceState.GetString(PasswordKey); | ||||
|  | ||||
| 				_pendingOtps = new List<string>(savedInstanceState.GetStringArrayList(PendingOtpsKey)); | ||||
| @@ -1319,77 +1412,66 @@ namespace keepass2android | ||||
|  | ||||
| 		private void UpdateOkButtonState() | ||||
| 		{ | ||||
| 		    bool enabled = false; | ||||
| 			switch (KeyProviderType) | ||||
| 			{ | ||||
| 				case KeyProviders.None: | ||||
| 					enabled = true; | ||||
| 					break; | ||||
| 				case KeyProviders.KeyFile: | ||||
| 					enabled = _keyFileOrProvider != "" || _password != ""; | ||||
| 					break; | ||||
| 				case KeyProviders.Otp: | ||||
| 					 | ||||
| 					enabled = true; | ||||
| 					if (_otpInfo == null) | ||||
| 						enabled = false; | ||||
| 					else | ||||
| 					{ | ||||
| 						int c = 0; | ||||
| 						foreach (int otpId in _otpTextViewIds) | ||||
| 						{ | ||||
| 							c++; | ||||
| 							var otpTextView = FindViewById<EditText>(otpId); | ||||
| 							if ((c <= _otpInfo.OtpsRequired) && (otpTextView.Text == "")) | ||||
| 							{ | ||||
| 								enabled = false; | ||||
| 								break; | ||||
| 							} | ||||
| 						}	 | ||||
| 					} | ||||
| 					 | ||||
| 					 | ||||
| 					break; | ||||
| 				case KeyProviders.OtpRecovery: | ||||
| 				case KeyProviders.ChalRecovery:				 | ||||
| 					enabled = FindViewById<EditText>(Resource.Id.pass_otpsecret).Text != ""; | ||||
| 					break; | ||||
| 				case KeyProviders.ChallengeXC: | ||||
| 					enabled = true; | ||||
| 					break; | ||||
|                 case KeyProviders.Challenge: | ||||
| 					enabled = _challengeSecret != null; | ||||
|                     break; | ||||
| 				default: | ||||
| 					throw new ArgumentOutOfRangeException(); | ||||
| 			} | ||||
| 		    bool enabled = true; | ||||
| 				if (KeyProviderTypes.Contains(KeyProviders.KeyFile)) | ||||
| 					enabled &= _keyFile != "" || _password != ""; | ||||
|  | ||||
| 		    if (KeyProviderTypes.Contains(KeyProviders.Otp)) | ||||
| 		    { | ||||
| 		        if (_otpInfo == null) | ||||
| 		            enabled = false; | ||||
| 		        else | ||||
| 		        { | ||||
| 		            int c = 0; | ||||
| 		            foreach (int otpId in _otpTextViewIds) | ||||
| 		            { | ||||
| 		                c++; | ||||
| 		                var otpTextView = FindViewById<EditText>(otpId); | ||||
| 		                if ((c <= _otpInfo.OtpsRequired) && (otpTextView.Text == "")) | ||||
| 		                { | ||||
| 		                    enabled = false; | ||||
| 		                    break; | ||||
| 		                } | ||||
| 		            } | ||||
| 		        } | ||||
| 		    } | ||||
|  | ||||
|  | ||||
| 		    if (KeyProviderTypes.Contains(KeyProviders.OtpRecovery) || KeyProviderTypes.Contains(KeyProviders.ChalRecovery)) | ||||
| 		    { | ||||
| 		        enabled &= FindViewById<EditText>(Resource.Id.pass_otpsecret).Text != ""; | ||||
| 		    } | ||||
|  | ||||
| 		    if (KeyProviderTypes.Contains(KeyProviders.Challenge)) | ||||
|                     enabled &= _challengeSecret != null; | ||||
| 			 | ||||
|             FindViewById(Resource.Id.pass_ok).Enabled = enabled; | ||||
|              | ||||
| 		} | ||||
|  | ||||
| 		private void UpdateKeyProviderUiState() | ||||
| 		{ | ||||
| 			FindViewById(Resource.Id.keyfileLine).Visibility = KeyProviderType == KeyProviders.KeyFile | ||||
| 			FindViewById(Resource.Id.keyfileLine).Visibility = KeyProviderHasKeyFile() | ||||
| 				                                                   ? ViewStates.Visible | ||||
| 				                                                   : ViewStates.Gone; | ||||
| 			if (KeyProviderType == KeyProviders.KeyFile) | ||||
| 			if (KeyProviderHasKeyFile()) | ||||
| 			{ | ||||
| 				UpdateKeyfileIocView(); | ||||
| 			} | ||||
| 			 | ||||
| 			FindViewById(Resource.Id.otpView).Visibility = KeyProviderType == KeyProviders.Otp | ||||
| 			FindViewById(Resource.Id.otpView).Visibility = KeyProviderTypes.Contains(KeyProviders.Otp) | ||||
| 				                                               ? ViewStates.Visible | ||||
| 				                                               : ViewStates.Gone; | ||||
|  | ||||
| 			FindViewById(Resource.Id.otpSecretLine).Visibility = (KeyProviderType == KeyProviders.OtpRecovery || KeyProviderType == KeyProviders.ChalRecovery) | ||||
| 			FindViewById(Resource.Id.otpSecretLine).Visibility = (KeyProviderTypes.Contains(KeyProviders.OtpRecovery) || KeyProviderTypes.Contains(KeyProviders.ChalRecovery)) | ||||
| 															   ? ViewStates.Visible | ||||
| 															   : ViewStates.Gone; | ||||
| 			if (KeyProviderType == KeyProviders.Otp) | ||||
| 			if (KeyProviderTypes.Contains(KeyProviders.Otp)) | ||||
| 			{ | ||||
| 				FindViewById(Resource.Id.otps_pending).Visibility = _pendingOtps.Count > 0 ? ViewStates.Visible : ViewStates.Gone; | ||||
| 			} | ||||
|  | ||||
| 			if (KeyProviderType == KeyProviders.Challenge)  | ||||
| 			if (KeyProviderTypes.Contains(KeyProviders.Challenge)) | ||||
| 			{ | ||||
| 				FindViewById (Resource.Id.otpView).Visibility = ViewStates.Visible; | ||||
| 				FindViewById(Resource.Id.otps_pending).Visibility = ViewStates.Gone; | ||||
| @@ -1397,7 +1479,12 @@ namespace keepass2android | ||||
| 			UpdateOkButtonState(); | ||||
| 		} | ||||
|  | ||||
| 		private void PerformLoadDatabase() | ||||
| 	    private bool KeyProviderHasKeyFile() | ||||
| 	    { | ||||
| 	        return KeyProviderTypes.Contains(KeyProviders.KeyFile); | ||||
| 	    } | ||||
|  | ||||
| 	    private void PerformLoadDatabase() | ||||
| 		{ | ||||
| 			_currentlyWaitingKey = null; | ||||
| 		    if (_performingLoad) | ||||
| @@ -1450,10 +1537,10 @@ namespace keepass2android | ||||
|  | ||||
| 				Handler handler = new Handler(); | ||||
| 				OnFinish onFinish = new AfterLoad(handler, this, _ioConnection); | ||||
| 				LoadDb task = (KeyProviderType == KeyProviders.Otp) | ||||
| 					? new SaveOtpAuxFileAndLoadDb(App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, _keyFileOrProvider, | ||||
| 				LoadDb task = (KeyProviderTypes.Contains(KeyProviders.Otp)) | ||||
| 					? new SaveOtpAuxFileAndLoadDb(App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, GetKeyProviderString(), | ||||
| 						onFinish, this) | ||||
| 					: new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, _keyFileOrProvider, onFinish); | ||||
| 					: new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, GetKeyProviderString(), onFinish); | ||||
| 				_loadDbFileTask = null; // prevent accidental re-use | ||||
|  | ||||
| 				SetNewDefaultFile(); | ||||
| @@ -1462,7 +1549,7 @@ namespace keepass2android | ||||
| 			} | ||||
| 			catch (Exception e) | ||||
| 			{ | ||||
| 				Kp2aLog.LogUnexpectedError(new Exception("cannot load database: "+e + ", c: " + (compositeKey != null) + (_ioConnection != null) + (_keyFileOrProvider != null), e)); | ||||
| 				Kp2aLog.LogUnexpectedError(new Exception("cannot load database: "+e + ", c: " + (compositeKey != null) + (_ioConnection != null) + (_keyFile != null), e)); | ||||
| 				throw; | ||||
| 			} | ||||
| 			 | ||||
| @@ -1474,13 +1561,13 @@ namespace keepass2android | ||||
| //no need to check for validity of password because if this method is called, the Ok button was enabled (i.e. there was a valid password) | ||||
| 			compositeKey = new CompositeKey(); | ||||
| 			compositeKey.AddUserKey(new KcpPassword(_password)); | ||||
| 			if (KeyProviderType == KeyProviders.KeyFile) | ||||
| 			if (KeyProviderTypes.Contains(KeyProviders.KeyFile)) | ||||
| 			{ | ||||
| 				try | ||||
| 				{ | ||||
| 					if (_keyFileOrProvider == "") | ||||
| 					if (_keyFile == "") | ||||
| 						throw new System.IO.FileNotFoundException(); | ||||
| 					var ioc = IOConnectionInfo.UnserializeFromString(_keyFileOrProvider); | ||||
| 					var ioc = IOConnectionInfo.UnserializeFromString(_keyFile); | ||||
| 					using (var stream = App.Kp2a.GetFileStorage(ioc).OpenFileForRead(ioc)) | ||||
| 					{ | ||||
| 						byte[] keyfileData = StreamToMemoryStream(stream).ToArray(); | ||||
| @@ -1500,7 +1587,7 @@ namespace keepass2android | ||||
| 					return false; | ||||
| 				} | ||||
| 			} | ||||
| 			else if (KeyProviderType == KeyProviders.Otp) | ||||
| 			if (KeyProviderTypes.Contains(KeyProviders.Otp)) | ||||
| 			{ | ||||
| 				try | ||||
| 				{ | ||||
| @@ -1517,7 +1604,7 @@ namespace keepass2android | ||||
| 				} | ||||
| 				compositeKey.AddUserKey(new KcpCustomKey(OathHotpKeyProv.Name, _otpInfo.Secret, true)); | ||||
| 			} | ||||
| 			else if ((KeyProviderType == KeyProviders.OtpRecovery) || (KeyProviderType == KeyProviders.ChalRecovery)) | ||||
| 			if ((KeyProviderTypes.Contains(KeyProviders.OtpRecovery)) || (KeyProviderTypes.Contains(KeyProviders.ChalRecovery))) | ||||
| 			{ | ||||
| 				Spinner stpDataFmtSpinner = FindViewById<Spinner>(Resource.Id.otpsecret_format_spinner); | ||||
| 				EditText secretEdit = FindViewById<EditText>(Resource.Id.pass_otpsecret); | ||||
| @@ -1533,11 +1620,11 @@ namespace keepass2android | ||||
| 					return false; | ||||
| 				} | ||||
| 			} | ||||
| 			else if (KeyProviderType == KeyProviders.Challenge) | ||||
| 			if (KeyProviderTypes.Contains(KeyProviders.Challenge)) | ||||
| 			{ | ||||
| 				compositeKey.AddUserKey(new KcpCustomKey(KeeChallengeProv.Name, _challengeSecret, true)); | ||||
| 			}  | ||||
| 			else if (KeyProviderType == KeyProviders.ChallengeXC) | ||||
| 			if (KeyProviderTypes.Contains(KeyProviders.ChallengeXC)) | ||||
| 			{ | ||||
| 				_currentlyWaitingKey = new ChallengeXCKey(this, RequestCodeChallengeYubikey); | ||||
| 				compositeKey.AddUserKey(_currentlyWaitingKey); | ||||
| @@ -1624,7 +1711,13 @@ namespace keepass2android | ||||
| 			base.OnStart(); | ||||
| 			_starting = true; | ||||
|  | ||||
| 		    AppTask.CanActivateSearchViewOnStart = true; | ||||
| 		    if (PreferenceManager.GetDefaultSharedPreferences(this) | ||||
| 		        .GetBoolean(GetString(Resource.String.UseKp2aKeyboardInKp2a_key), false)) | ||||
| 		    { | ||||
| 		        CopyToClipboardService.ActivateKeyboard(this); | ||||
| 		    } | ||||
|  | ||||
|                 AppTask.CanActivateSearchViewOnStart = true; | ||||
|             DonateReminder.ShowDonateReminderIfAppropriate(this); | ||||
| 			 | ||||
| 			 | ||||
| @@ -1660,7 +1753,7 @@ namespace keepass2android | ||||
| 			AppTask.ToBundle(outState); | ||||
| 			outState.PutBoolean(ShowpasswordKey, _showPassword); | ||||
|  | ||||
| 			outState.PutString(KeyFileOrProviderKey, _keyFileOrProvider); | ||||
| 			outState.PutString(KeyFileOrProviderKey, GetKeyProviderString()); | ||||
| 			outState.PutString(PasswordKey, _password); | ||||
| 			outState.PutStringArrayList(PendingOtpsKey, _pendingOtps); | ||||
| 			if (_otpInfo != null) | ||||
| @@ -1695,7 +1788,7 @@ namespace keepass2android | ||||
| 			{ | ||||
| 				string otp = intent.GetStringExtra(Intents.OtpExtraKey); | ||||
| 				_keepPasswordInOnResume = true; | ||||
| 				if (this.KeyProviderType == KeyProviders.Otp) | ||||
| 				if (KeyProviderTypes.Contains(KeyProviders.Otp)) | ||||
| 				{ | ||||
| 				 | ||||
| 					if (_otpInfo == null) | ||||
| @@ -1800,7 +1893,7 @@ namespace keepass2android | ||||
|  | ||||
| 			UpdateOkButtonState(); | ||||
|  | ||||
| 			if (KeyProviderType == KeyProviders.Challenge) | ||||
| 			if (KeyProviderTypes.Contains(KeyProviders.Challenge)) | ||||
| 			{ | ||||
| 				FindViewById(Resource.Id.otpInitView).Visibility = _challengeSecret == null ? ViewStates.Visible : ViewStates.Gone; | ||||
| 			} | ||||
| @@ -1835,7 +1928,7 @@ namespace keepass2android | ||||
| 						if (_loadDbFileTask == null && _prefs.GetBoolean(GetString(Resource.String.PreloadDatabaseEnabled_key), true)) | ||||
| 						{ | ||||
| 							// Create task to kick off file loading while the user enters the password | ||||
| 							_loadDbFileTask = Task.Factory.StartNew<MemoryStream>(PreloadDbFile); | ||||
| 							_loadDbFileTask = Task.Factory.StartNew(PreloadDbFile); | ||||
| 							_loadDbTaskOffline = App.Kp2a.OfflineMode; | ||||
| 						} | ||||
| 					} | ||||
| @@ -1860,7 +1953,7 @@ namespace keepass2android | ||||
| 			EditText pwd = (EditText)FindViewById(Resource.Id.password_edit); | ||||
| 			pwd.PostDelayed(() => | ||||
| 			{ | ||||
| 				InputMethodManager keyboard = (InputMethodManager)GetSystemService(Context.InputMethodService); | ||||
| 				InputMethodManager keyboard = (InputMethodManager)GetSystemService(InputMethodService); | ||||
| 				if (showKeyboard) | ||||
| 					keyboard.ShowSoftInput(pwd, 0); | ||||
| 				else | ||||
| @@ -1904,7 +1997,7 @@ namespace keepass2android | ||||
| 			{ | ||||
|                 //exception can happen here if the app was restored from Google Backup (including preferences) but no fingerprint data is there. | ||||
| 				btn.SetImageResource(Resource.Drawable.ic_fingerprint_error); | ||||
| 			    Kp2aLog.Log("failed to init fingerprint unlock:" + e.ToString()); | ||||
| 			    Kp2aLog.Log("failed to init fingerprint unlock:" + e); | ||||
|                 string error = GetString(Resource.String.FingerprintInitFailed) + " " + | ||||
| 			                   GetString(Resource.String.fingerprint_reenable2); | ||||
| 			     | ||||
| @@ -1942,32 +2035,12 @@ namespace keepass2android | ||||
| 			 | ||||
| 		} | ||||
| 			 | ||||
| 		private String GetKeyFile(String filename) { | ||||
| 		private String LoadKeyProviderStringForIoc(String filename) { | ||||
| 			if ( _rememberKeyfile ) { | ||||
| 				string keyfile = App.Kp2a.FileDbHelper.GetKeyFileForFile(filename); | ||||
| 				if (String.IsNullOrEmpty(keyfile)) | ||||
| 					return null; //signal no key file | ||||
|  | ||||
| 				if (KeyProviderType == KeyProviders.KeyFile) | ||||
| 				{ | ||||
| 					//test if the filename is properly encoded.  | ||||
| 					try | ||||
| 					{ | ||||
| 						Kp2aLog.Log("test if stored filename is ok"); | ||||
| 						IOConnectionInfo.UnserializeFromString(keyfile); | ||||
| 						Kp2aLog.Log("...ok"); | ||||
| 					} | ||||
| 					catch (Exception e) | ||||
| 					{ | ||||
| 						//it's not. This is probably because we're upgrading from app version <= 45 | ||||
| 						//where the keyfile was stored plain text and not serialized | ||||
| 						Kp2aLog.Log("no, it's not: " + e.GetType().Name); | ||||
| 						var serializedKeyFile = IOConnectionInfo.SerializeToString(IOConnectionInfo.FromPath(keyfile)); | ||||
| 						Kp2aLog.Log("now it is!"); | ||||
| 						return serializedKeyFile; | ||||
|  | ||||
| 					}	 | ||||
| 				} | ||||
|                  | ||||
| 				return keyfile; | ||||
| 			} else { | ||||
| 				return null; | ||||
| @@ -2094,8 +2167,8 @@ namespace keepass2android | ||||
| 			    { | ||||
| 			        if (_act._prefs.GetBoolean(IoUtil.GetIocPrefKey(_ioConnection, "has_local_backup"), false)) | ||||
| 			        { | ||||
| 			            Java.Lang.Object changeDb = _act.GetString(Resource.String.menu_change_db); | ||||
| 			            Message += _act.GetString(Resource.String.HintLocalBackupOtherError, new Java.Lang.Object[] { changeDb }); | ||||
| 			            Object changeDb = _act.GetString(Resource.String.menu_change_db); | ||||
| 			            Message += _act.GetString(Resource.String.HintLocalBackupOtherError, changeDb); | ||||
| 			        } | ||||
|  | ||||
|                 } | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| 	<application android:label="keepass2android"  | ||||
| 	android:icon="@mipmap/ic_launcher_online" | ||||
| 	android:roundIcon="@mipmap/ic_launcher_online_round" | ||||
| 	android:networkSecurityConfig="@xml/network_security_config" | ||||
| 	> | ||||
| 		 | ||||
| 		<activity android:name="com.dropbox.core.android.AuthActivity" android:launchMode="singleTask" android:configChanges="orientation|keyboard"> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android"  | ||||
| 			android:versionCode="124"  | ||||
| 			android:versionName="1.06c"  | ||||
| 			android:versionCode="127"  | ||||
| 			android:versionName="1.06f"  | ||||
| 			package="keepass2android.keepass2android"  | ||||
| 			android:installLocation="auto"> | ||||
| 	<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26" /> | ||||
| @@ -11,6 +11,8 @@ | ||||
| 	<application android:label="keepass2android"  | ||||
| 	android:icon="@mipmap/ic_launcher_online" | ||||
| 	android:roundIcon="@mipmap/ic_launcher_online_round" | ||||
| 	android:networkSecurityConfig="@xml/network_security_config" | ||||
|  | ||||
| 	> | ||||
| 		<activity android:name="com.dropbox.core.android.AuthActivity" android:launchMode="singleTask" android:configChanges="orientation|keyboard"> | ||||
| 			<intent-filter> | ||||
|   | ||||
| @@ -7,7 +7,11 @@ | ||||
| 	<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" /> | ||||
|   <permission android:description="@string/permission_desc2" android:icon="@drawable/ic_launcher" android:label="KP2A entry search" android:name="keepass2android.keepass2android_nonet.permission.KP2aInternalSearch" android:protectionLevel="signature" /> | ||||
|   <permission android:description="@string/permission_desc3" android:icon="@drawable/ic_launcher" android:label="KP2A choose autofill dataset" android:name="keepass2android.keepass2android_nonet.permission.Kp2aChooseAutofill" android:protectionLevel="signature" /> | ||||
| 	<application android:label="keepass2android" android:icon="@mipmap/ic_launcher_offline"> | ||||
| 	<application  | ||||
| 		android:label="keepass2android"  | ||||
| 		android:icon="@mipmap/ic_launcher_offline" | ||||
| 		android:networkSecurityConfig="@xml/network_security_config" | ||||
| 	> | ||||
| 		<provider android:name="group.pals.android.lib.ui.filechooser.providers.localfile.LocalFileProvider" android:authorities="keepass2android.keepass2android_nonet.android-filechooser.localfile" android:exported="false" /> | ||||
| 		<provider android:name="group.pals.android.lib.ui.filechooser.providers.history.HistoryProvider" android:authorities="keepass2android.keepass2android_nonet.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"> | ||||
|   | ||||
| @@ -39,6 +39,26 @@ | ||||
|             android:layout_height="wrap_content" | ||||
|             android:singleLine="true" | ||||
|             android:hint="@string/hint_username" /> | ||||
|  | ||||
|  | ||||
|   <LinearLayout | ||||
|     android:orientation="horizontal" | ||||
|     android:layout_width="fill_parent" | ||||
|     android:layout_height="wrap_content"> | ||||
|  | ||||
|     <TextView | ||||
|       android:id="@+id/auth_mode_title" | ||||
|       android:layout_width="wrap_content" | ||||
|       android:layout_height="wrap_content" | ||||
|       android:text="@string/sftp_auth_mode" /> | ||||
|  | ||||
|     <Spinner | ||||
|       android:id="@+id/sftp_auth_mode_spinner" | ||||
|       android:layout_width="fill_parent" | ||||
|       android:layout_height="wrap_content" | ||||
|       android:layout_marginLeft="-4dp" | ||||
|       android:entries="@array/sftp_auth_modes" /> | ||||
|   </LinearLayout> | ||||
| 		 | ||||
| 	<EditText | ||||
|             android:id="@+id/sftp_password" | ||||
| @@ -48,6 +68,11 @@ | ||||
|             android:singleLine="true" | ||||
|             android:hint="@string/hint_pass" | ||||
| 	          android:importantForAccessibility="no"/> | ||||
|   <Button  android:id="@+id/send_public_key_button" | ||||
|            android:layout_width="fill_parent" | ||||
|            android:layout_height="wrap_content" | ||||
|            android:text="@string/send_public_key" /> | ||||
|    | ||||
| 		 | ||||
| 		<TextView android:id="@+id/initial_dir" | ||||
|             android:layout_width="wrap_content" | ||||
|   | ||||
| @@ -27,6 +27,11 @@ | ||||
|         android:icon="@drawable/ic_menu_view" | ||||
|         app:showAsAction="ifRoom" | ||||
|     /> | ||||
|   <item android:id="@+id/menu_delete" | ||||
|         android:icon="@drawable/ic_menu_delete" | ||||
|         android:title="@string/menu_delete" | ||||
|         app:showAsAction="ifRoom" | ||||
|   /> | ||||
|     <item android:id="@+id/menu_donate" | ||||
|         android:title="@string/menu_donate" | ||||
|         app:showAsAction="ifRoom" | ||||
|   | ||||
| @@ -917,6 +917,7 @@ Erstes öffentliches Release</string> | ||||
|     <item>Passwort + Challenge-Response</item> | ||||
|     <item>Passwort + Challenge-Response-Secret (Recovery-Modus)</item> | ||||
|     <item>Passwort + Challenge-Response für Keepass XC</item> | ||||
|     <item>Password + Schlüsseldatei + Challenge-Response für Keepass XC</item> | ||||
|   </string-array> | ||||
|   <string-array name="AcceptAllServerCertificates_options"> | ||||
|     <item>Fehler bei Zertifikatsvalidierung ignorieren</item> | ||||
|   | ||||
| @@ -114,8 +114,10 @@ | ||||
| 	<string name="UseFileTransactions_key">UseFileTransactions</string> | ||||
| 	<string name="LockWhenScreenOff_key">LockWhenScreenOff</string> | ||||
| 	<string name="LockWhenNavigateBack_key">kp2a_switch_rootedLockWhenNavigateBack</string> | ||||
|   <string name="UseKp2aKeyboardInKp2a_key">UseKp2aKeyboardInKp2a</string> | ||||
|    | ||||
|  | ||||
| 	<string name="NoDonateOption_key">NoDonateOption</string> | ||||
|   <string name="NoDonateOption_key">NoDonateOption</string> | ||||
|   <string name="NoDonationReminder_key">NoDonationReminder</string> | ||||
|  | ||||
| 	<string name="UseOfflineCache_key">UseOfflineCache</string> | ||||
|   | ||||
| @@ -346,6 +346,11 @@ | ||||
| 	<string name="LockWhenNavigateBack_title">Lock when leaving app</string> | ||||
| 	<string name="LockWhenNavigateBack_summary">Lock the database when leaving the app by pressing the back button.</string> | ||||
|  | ||||
|   <string name="UseKp2aKeyboardInKp2a_title">Use built-in keyboard inside Keepass2Android</string> | ||||
|   <string name="UseKp2aKeyboardInKp2a_summary">If you do not trust your standard keyboard provider, check this option to use the built-in keyboard when entering your master password or editing entries.</string> | ||||
|  | ||||
|    | ||||
|  | ||||
|   <string name="ActivateSearchViewOnStart_title">Activate search field on start</string> | ||||
|   <string name="ActivateSearchViewOnStart_summary">Activates search field in the group view after unlocking or when searching for an entry</string> | ||||
|  | ||||
| @@ -510,6 +515,8 @@ | ||||
| 	<string name="hint_sftp_port">port</string> | ||||
| 	<string name="initial_directory">Initial directory (optional):</string> | ||||
| 	<string name="enter_sftp_login_title">Enter SFTP login data:</string> | ||||
|   <string name="sftp_auth_mode">Authentication mode</string> | ||||
|   <string name="send_public_key">Send public key...</string> | ||||
|  | ||||
|   <string name="enter_ftp_login_title">Enter FTP login data:</string> | ||||
|  | ||||
| @@ -1107,7 +1114,12 @@ Initial public release | ||||
| 		<item>Password + Challenge-Response</item> | ||||
| 		<item>Password + Challenge-Response secret (recovery mode)</item> | ||||
| 	  <item>Password + Challenge-Response for Keepass XC</item> | ||||
| 	  <item>Password + Key file + Challenge-Response for Keepass XC</item> | ||||
| 	</string-array> | ||||
|   <string-array name="sftp_auth_modes"> | ||||
|     <item>Password</item> | ||||
|     <item>Private/Public key</item> | ||||
|   </string-array> | ||||
| 	<string-array name="AcceptAllServerCertificates_options"> | ||||
| 		<item>Ignore certificate validation failures</item> | ||||
| 		<item>Warn when validation fails</item> | ||||
|   | ||||
| @@ -0,0 +1,9 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <network-security-config> | ||||
|   <base-config cleartextTrafficPermitted="true"> | ||||
|     <trust-anchors> | ||||
|       <certificates src="system" /> | ||||
|       <certificates src="user" /> | ||||
|     </trust-anchors> | ||||
|   </base-config> | ||||
| </network-security-config> | ||||
| @@ -200,6 +200,14 @@ | ||||
| 				 android:title="@string/ClearPasswordOnLeave_title" | ||||
| 				 android:key="@string/ClearPasswordOnLeave_key" /> | ||||
|  | ||||
| 		  <CheckBoxPreference | ||||
| 		    android:enabled="true" | ||||
| 		    android:persistent="true" | ||||
| 		    android:summary="@string/UseKp2aKeyboardInKp2a_summary" | ||||
| 		    android:defaultValue="false" | ||||
| 		    android:title="@string/UseKp2aKeyboardInKp2a_title" | ||||
| 		    android:key="@string/UseKp2aKeyboardInKp2a_key" /> | ||||
|  | ||||
|  | ||||
| 		</PreferenceScreen> | ||||
| 		<PreferenceScreen | ||||
|   | ||||
| @@ -586,7 +586,7 @@ namespace keepass2android | ||||
| 							new DropboxAppFolderFileStorage(Application.Context, this), | ||||
| 							new GoogleDriveFileStorage(Application.Context, this), | ||||
| 							new OneDriveFileStorage(Application.Context, this), | ||||
| 							new SftpFileStorage(this), | ||||
| 							new SftpFileStorage(Application.Context, this), | ||||
| 							new NetFtpFileStorage(Application.Context, this), | ||||
| 							new WebDavFileStorage(this), | ||||
| 							new PCloudFileStorage(Application.Context, this), | ||||
|   | ||||
| @@ -828,6 +828,10 @@ | ||||
|     <Folder Include="SupportLib\" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\AdalBindings\AdalBindings.csproj"> | ||||
|       <Project>{0b109c0e-0514-4340-8779-5bd6a0dde84e}</Project> | ||||
|       <Name>AdalBindings</Name> | ||||
|     </ProjectReference> | ||||
|     <ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj"> | ||||
|       <Project>{48574278-4779-4B3A-A9E4-9CF1BC285D0B}</Project> | ||||
|       <Name>JavaFileStorageBindings</Name> | ||||
| @@ -1869,6 +1873,9 @@ | ||||
|   <ItemGroup> | ||||
|     <AndroidResource Include="Resources\drawable-xhdpi\vdots_bright.png" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <AndroidResource Include="Resources\xml\network_security_config.xml" /> | ||||
|   </ItemGroup> | ||||
|   <Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" /> | ||||
|   <Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" /> | ||||
|   <Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''"> | ||||
| @@ -1917,4 +1924,4 @@ | ||||
|   <Import Project="..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Animated.Vector.Drawable.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Animated.Vector.Drawable.targets')" /> | ||||
|   <Import Project="..\packages\Xamarin.Android.Support.v7.AppCompat.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.v7.AppCompat.targets" Condition="Exists('..\packages\Xamarin.Android.Support.v7.AppCompat.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.v7.AppCompat.targets')" /> | ||||
|   <Import Project="..\packages\Xamarin.Android.Support.Design.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Design.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Design.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Design.targets')" /> | ||||
| </Project> | ||||
| </Project> | ||||
		Reference in New Issue
	
	Block a user
	 PhilippC
					PhilippC