Compare commits

..

10 Commits

Author SHA1 Message Date
Philipp Crocoll
832d3b3a95 1.05d release for nonet 2018-06-23 09:07:47 +02:00
Philipp Crocoll
37867634cd Merge branch 'master' into nonet
Conflicts:
	src/keepass2android/Properties/AndroidManifest_nonet.xml
2018-06-18 13:08:07 +02:00
Philipp Crocoll
d9713f8e18 switch to using Release build type instead of ReleaseNoNet (separation no longer required because a custom branch exists for the offline variant) 2018-02-28 06:06:26 +01:00
Philipp Crocoll
c583b58cb9 adjust manifest version for 1.04b release 2018-02-27 06:06:35 +01:00
Philipp Crocoll
bfeaf5dbf5 Merge branch '1.04' into nonet
Conflicts:
	src/keepass2android/Properties/AndroidManifest_nonet.xml
2018-02-21 05:58:01 +01:00
Philipp Crocoll
0907fa5685 manifest for 1.03-nonet release 2017-12-02 15:30:04 +01:00
Philipp Crocoll
ff8dc76c75 Merge branch 'master' into nonet
Conflicts:
	docs/README.md
2017-12-02 14:25:37 +01:00
Philipp Crocoll
0b09e2790f remove online file storages from project file 2017-10-25 06:49:02 +02:00
Philipp Crocoll
781350aa5f manifest for 1.02 release 2017-10-25 06:24:01 +02:00
Philipp Crocoll
9716130336 remove references to libraries only required for online build, adjust build script and README 2017-10-25 06:23:53 +02:00
206 changed files with 2433 additions and 11524 deletions

View File

@@ -1,6 +0,0 @@
files:
- source: src/keepass2android/Resources/values/strings.xml
translation: >-
/src/keepass2android/Resources/values-%two_letters_code%/%original_file_name%
translate_attributes: '0'
content_segmentation: '0'

View File

@@ -7,12 +7,11 @@ If you think something is missing in the documentation, please create an issue a
If you store important information using Keepass2Android, you should know a little bit about what's going on:
* Keepass2Android stores your password in an encrypted file. It is *your responsibility* to backup this file regularly and safely.
* There is no way for anyone, including the app's author, to access the information stored in your password database without
* having the database file
* knowing the master password (and additional second factor if you chose one)
This means that **if you forget the master password, your database is lost**! So make sure you remember the password and retain any second factor method (if one is used).
* You might also want to think about:
* What happens if I have an accident? Should any trusted person be able to access my database?
* What happens if my phone gets lost or stolen? Do I know how to recover my database from a backup or the cloud?
** having the database file
** knowing the master password (and additional second factor if you chose one)
This means that **if you forget the master password, your database is lost**! So make sure you remember the password. You might also want to think about:
** What happens if I have an accident? Should any trusted person be able to access my database?
** What happens if my phone gets lost or stolen? Do I know how to recover my database from a backup or the cloud?
# Getting started

View File

@@ -4,28 +4,28 @@
on how to set up a Keepass 2 database with Yubikey/OTP protection.<br>
<br>
After successful setup you should have the database file, e.g. yubi.kdbx, and the OTP auxiliary file, e.g. yubi.otp.xml, both in the same folder.<br>
<a href="How to use Keepass2Android with YubiKey NEO_OTPAuxFile_2.png"><img title="OTPAuxFile" src="How to use Keepass2Android with YubiKey NEO_OTPAuxFile_thumb.png" alt="OTPAuxFile" width="513" height="40" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p>
<a href="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767825"><img title="OTPAuxFile" src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767826" alt="OTPAuxFile" width="513" height="40" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p>
<p>Make sure you make <strong>both files</strong> available to Keepass2Android, e.g. by placing them both in your Dropbox.</p>
<p>Now you should check your NDEF setup of the Yubikey NEO. Therefore, go to the Tools menu in the Yubico Personalization Utility. Select the same slot as used for OTPs with Keepass 2. The default setting for NDEF type and payload should work. If you experience
problems, you may use the configuration as shown in this screenshot or simply press the &ldquo;Reset&rdquo; button:</p>
<p><a href="How to use Keepass2Android with YubiKey NEO_image_2.png"><img title="image" src="How to use Keepass2Android with YubiKey NEO_image_thumb.png" alt="image" width="760" height="622" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p>
<p><a href="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767911"><img title="image" src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767912" alt="image" width="760" height="622" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p>
<p><br>
<br>
In Keepass2Android, select &quot;Open file&quot; and locate your database file, e.g. yubi.kdbx.<br>
<br>
In the password screen under &quot;Select master key type&quot; select &quot;Password &#43; OTP&quot;.</p>
<p><a href="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-38-50_2.png"><img title="Screenshot_2013-12-13-06-38-50" src="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-38-50_thumb.png" alt="Screenshot_2013-12-13-06-38-50" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p>
<p><a href="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767913"><img title="Screenshot_2013-12-13-06-38-50" src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767914" alt="Screenshot_2013-12-13-06-38-50" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p>
<p>Click &quot;Load auxiliary OTP file&quot;. This is required to load the information how many OTPs must be entered. As loading the file might require user action in some cases, this is not performed automatically.<br>
<a href="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-38-12_2.png"><img title="Screenshot_2013-12-13-06-38-12" src="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-38-12_thumb.png" alt="Screenshot_2013-12-13-06-38-12" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a><br>
<a href="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767915"><img title="Screenshot_2013-12-13-06-38-12" src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767916" alt="Screenshot_2013-12-13-06-38-12" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a><br>
After loading the OTP auxiliary file, you should see a few text fields for entering the OTPs. Now swipe your YubiKey NEO at the back of your Android device. If you have multiple apps which can handle NFC actions, you might be prompted to select which app to
use. Select Keepass2Android in this case. Swipe your YubiKey again until all OTP fields are filled. Note: You don't need to select the next text field, this is done automatically!<br>
<a href="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-38-36_2.png"><img title="Screenshot_2013-12-13-06-38-36" src="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-38-36_thumb.png" alt="Screenshot_2013-12-13-06-38-36" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a><br>
<a href="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767917"><img title="Screenshot_2013-12-13-06-38-36" src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767918" alt="Screenshot_2013-12-13-06-38-36" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a><br>
Don't forget to also enter your password and click OK. You will see the &ldquo;Saving auxiliary OTP file&hellip;&rdquo; dialog. Note that there is some encryption envolved which is probably fast on your PC but might take some time on your mobile device. You
can reduce the look-ahead window length to speed this up.<br>
<a href="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-39-47_2.png"><img title="Screenshot_2013-12-13-06-39-47" src="How to use Keepass2Android with YubiKey NEO_Screenshot_2013-12-13-06-39-47_thumb.png" alt="Screenshot_2013-12-13-06-39-47" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p>
<a href="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767919"><img title="Screenshot_2013-12-13-06-39-47" src="http://download-codeplex.sec.s-msft.com/Download?ProjectName=keepass2android&DownloadId=767920" alt="Screenshot_2013-12-13-06-39-47" width="204" height="360" border="0" style="padding-top:0px; padding-left:0px; display:inline; padding-right:0px; border:0px"></a></p>
<h2>&nbsp;</h2>
<h2>A note about offline access</h2>
<p>If your database is stored in the cloud or on the web, you can still access it if you have enabled file caching (which is on by default). With OTPs, this becomes a little bit more complicated: If you repeatedly open your datbase while being offline, the
OTP counter stored on the Yubikey will be increased. Don&rsquo;t forget to synchronize the database (which will also synchronize the OTP auxiliary file) as soon as possible to avoid problems with accessing your database on other devices! If you often need
to open the database while you&rsquo;re offline, consider increasing the look-ahead window length!</p>
</div><div class="ClearBoth"></div>
</div><div class="ClearBoth"></div>

View File

@@ -15,4 +15,4 @@ Beta-releases can be obtained by opting in to the [Beta testing channel](https:/
# How do I learn more?
Please see the [documentation](Documentation.md).
[![Build Status](https://www.bitrise.io/app/43a23ab54dee9f7e/status.svg?token=2vryTsMQzTX3XRPikhgRwA&branch=master)](https://www.bitrise.io/app/43a23ab54dee9f7e)
[![Build Status](https://www.bitrise.io/app/43a23ab54dee9f7e/status.svg?token=2vryTsMQzTX3XRPikhgRwA&branch=nonet)](https://www.bitrise.io/app/43a23ab54dee9f7e)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -1,64 +0,0 @@
<?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>

View File

@@ -1,48 +0,0 @@
Additions allow you to add arbitrary C# to the generated classes
before they are compiled. This can be helpful for providing convenience
methods or adding pure C# classes.
== Adding Methods to Generated Classes ==
Let's say the library being bound has a Rectangle class with a constructor
that takes an x and y position, and a width and length size. It will look like
this:
public partial class Rectangle
{
public Rectangle (int x, int y, int width, int height)
{
// JNI bindings
}
}
Imagine we want to add a constructor to this class that takes a Point and
Size structure instead of 4 ints. We can add a new file called Rectangle.cs
with a partial class containing our new method:
public partial class Rectangle
{
public Rectangle (Point location, Size size) :
this (location.X, location.Y, size.Width, size.Height)
{
}
}
At compile time, the additions class will be added to the generated class
and the final assembly will a Rectangle class with both constructors.
== Adding C# Classes ==
Another thing that can be done is adding fully C# managed classes to the
generated library. In the above example, let's assume that there isn't a
Point class available in Java or our library. The one we create doesn't need
to interact with Java, so we'll create it like a normal class in C#.
By adding a Point.cs file with this class, it will end up in the binding library:
public class Point
{
public int X { get; set; }
public int Y { get; set; }
}

View File

@@ -1,24 +0,0 @@
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".

Binary file not shown.

View File

@@ -1,30 +0,0 @@
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")]

View File

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

View File

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

View File

@@ -1,13 +0,0 @@
<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>

View File

@@ -26,7 +26,6 @@
android:hint="@string/http_auth_dialog_password"
android:inputType="textPassword"
android:paddingTop="10dp"
android:paddingBottom="20dp"
android:importantForAccessibility="no" />
android:paddingBottom="20dp" />
</LinearLayout>

View File

@@ -60,6 +60,7 @@
</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" />
@@ -80,13 +81,6 @@
<Visible>False</Visible>
</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>
<EmbeddedReferenceJar Include="Jars\okhttp-digest-1.7.jar" />
</ItemGroup>

View File

@@ -11,8 +11,6 @@
<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']" />

View File

@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2009
VisualStudioVersion = 15.0.27130.2010
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassLib2Android", "KeePassLib2Android\KeePassLib2Android.csproj", "{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}"
EndProject
@@ -13,8 +13,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kp2aBusinessLogic", "Kp2aBu
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TwofishCipher", "TwofishCipher\TwofishCipher.csproj", "{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JavaFileStorageBindings", "JavaFileStorageBindings\JavaFileStorageBindings.csproj", "{48574278-4779-4B3A-A9E4-9CF1BC285D0B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AndroidFileChooserBinding", "AndroidFileChooserBinding\AndroidFileChooserBinding.csproj", "{3C0F7FE5-639F-4422-A087-8B26CF862D1B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KP2AKdbLibraryBinding", "KP2AKdbLibraryBinding\KP2AKdbLibraryBinding.csproj", "{70D3844A-D9FA-4A64-B205-A84C6A822196}"
@@ -23,14 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginSdkBinding", "PluginS
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZlibAndroid", "ZlibAndroid\ZlibAndroid.csproj", "{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.FtpClient.Android", "netftpandroid\System.Net.FtpClient\System.Net.FtpClient.Android.csproj", "{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamsungPass", "SamsungPass\Xamarin.SamsungPass\SamsungPass\SamsungPass.csproj", "{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}"
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
@@ -113,8 +105,8 @@ Global
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|Win32.Build.0 = Release|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|x64.ActiveCfg = Release|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|x64.Build.0 = Release|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.ActiveCfg = Debug|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.Build.0 = Debug|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
@@ -155,30 +147,6 @@ Global
{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Win32.ActiveCfg = Debug|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|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}.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 = 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
@@ -191,8 +159,8 @@ Global
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Win32.ActiveCfg = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|x64.ActiveCfg = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
@@ -209,8 +177,8 @@ Global
{70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|Win32.ActiveCfg = Release|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|x64.ActiveCfg = Release|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
@@ -227,8 +195,8 @@ Global
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Win32.ActiveCfg = Release|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|x64.ActiveCfg = Release|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
@@ -257,24 +225,6 @@ Global
{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}.ReleaseNoNet|Win32.Build.0 = Release|Any CPU
{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}.ReleaseNoNet|x64.Build.0 = Release|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Debug|Win32.ActiveCfg = Debug|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Debug|x64.ActiveCfg = Debug|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Release|Any CPU.Build.0 = Release|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Release|Win32.ActiveCfg = Release|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Release|x64.ActiveCfg = Release|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@@ -293,54 +243,6 @@ 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
{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

View File

@@ -10,7 +10,6 @@ using Android.OS;
using Android.Provider;
using Java.IO;
using KeePassLib.Serialization;
using KeePassLib.Utility;
using Console = System.Console;
namespace keepass2android.Io
@@ -78,9 +77,8 @@ namespace keepass2android.Io
public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc)
{
return UrlUtil.StripExtension(
UrlUtil.GetFileName(ioc.Path));
}
return "";
}
public bool RequiresCredentials(IOConnectionInfo ioc)
{

View File

@@ -345,7 +345,57 @@ namespace keepass2android.Io
private class CachedWriteTransaction: IWriteTransaction
{
private class CachedWriteMemoryStream : MemoryStream
{
private readonly IOConnectionInfo ioc;
private readonly CachingFileStorage _cachingFileStorage;
private readonly bool _useFileTransaction;
private bool _closed;
public CachedWriteMemoryStream(IOConnectionInfo ioc, CachingFileStorage cachingFileStorage, bool useFileTransaction)
{
this.ioc = ioc;
_cachingFileStorage = cachingFileStorage;
_useFileTransaction = useFileTransaction;
}
public override void Close()
{
if (_closed) return;
//write file to cache:
//(note: this might overwrite local changes. It's assumed that a sync operation or check was performed before
string hash;
using (var hashingStream = new HashingStreamEx(File.Create(_cachingFileStorage.CachedFilePath(ioc)), true, new SHA256Managed()))
{
Position = 0;
CopyTo(hashingStream);
hashingStream.Close();
hash = MemUtil.ByteArrayToHexString(hashingStream.Hash);
}
File.WriteAllText(_cachingFileStorage.VersionFilePath(ioc), hash);
//update file on remote. This might overwrite changes there as well, see above.
Position = 0;
if (_cachingFileStorage.IsCached(ioc))
{
//if the file already is in the cache, it's ok if writing to remote fails.
_cachingFileStorage.TryUpdateRemoteFile(this, ioc, _useFileTransaction, hash);
}
else
{
//if not, we don't accept a failure (e.g. invalid credentials would always remain a problem)
_cachingFileStorage.UpdateRemoteFile(this, ioc, _useFileTransaction, hash);
}
base.Close();
_closed = true;
}
}
private readonly IOConnectionInfo _ioc;
private readonly bool _useFileTransaction;
@@ -379,48 +429,17 @@ namespace keepass2android.Io
public Stream OpenFile()
{
_memoryStream = new MemoryStream();
_memoryStream = new CachedWriteMemoryStream(_ioc, _cachingFileStorage, _useFileTransaction);
return _memoryStream;
}
public void CommitWrite()
{
//the transaction is committed in the stream's Close
_committed = true;
_memoryStream.Close();
//write file to cache:
//(note: this might overwrite local changes. It's assumed that a sync operation or check was performed before
byte[] output = _memoryStream.ToArray();
string hash;
using (var hashingStream = new HashingStreamEx(File.Create(_cachingFileStorage.CachedFilePath(_ioc)), true, new SHA256Managed()))
{
hashingStream.Write(output, 0, output.Length);
hashingStream.Close();
hash = MemUtil.ByteArrayToHexString(hashingStream.Hash);
}
File.WriteAllText(_cachingFileStorage.VersionFilePath(_ioc), hash);
//create another memory stream which is open for reading again
MemoryStream openMemStream = new MemoryStream(output);
//update file on remote. This might overwrite changes there as well, see above.
if (_cachingFileStorage.IsCached(_ioc))
{
//if the file already is in the cache, it's ok if writing to remote fails.
_cachingFileStorage.TryUpdateRemoteFile(openMemStream, _ioc, _useFileTransaction, hash);
}
else
{
//if not, we don't accept a failure (e.g. invalid credentials would always remain a problem)
_cachingFileStorage.UpdateRemoteFile(openMemStream, _ioc, _useFileTransaction, hash);
}
openMemStream.Dispose();
}
}
}
public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction)

View File

@@ -2,12 +2,12 @@ namespace keepass2android.Io
{
public partial class DropboxFileStorage
{
private const string AppKey = "dummy";
private const string AppSecret = "dummy";
private const string AppKey = "";
private const string AppSecret = "";
}
public partial class DropboxAppFolderFileStorage
{
private const string AppKey = "dummy";
private const string AppSecret = "dummy";
private const string AppKey = "";
private const string AppSecret = "";
}
}
}

View File

@@ -1,23 +0,0 @@
using Android.Content;
#if !EXCLUDE_JAVAFILESTORAGE
namespace keepass2android.Io
{
public partial class PCloudFileStorage: JavaFileStorage
{
private const string ClientId = "CkRWTQXY6Lm";
public PCloudFileStorage(Context ctx, IKp2aApp app) :
base(new Keepass2android.Javafilestorage.PCloudFileStorage(ctx, ClientId), app)
{
}
public override bool UserShouldBackup
{
get { return false; }
}
}
}
#endif

View File

@@ -5,8 +5,8 @@ namespace keepass2android.Io
{
public class SftpFileStorage: JavaFileStorage
{
public SftpFileStorage(Context ctx, IKp2aApp app) :
base(new Keepass2android.Javafilestorage.SftpStorage(ctx.ApplicationContext), app)
public SftpFileStorage(IKp2aApp app) :
base(new Keepass2android.Javafilestorage.SftpStorage(), app)
{
}

View File

@@ -30,8 +30,7 @@ namespace keepass2android.Io
yield return "http";
yield return "https";
yield return "owncloud";
yield return "nextcloud";
}
}
}
public override bool UserShouldBackup
@@ -39,15 +38,12 @@ namespace keepass2android.Io
get { return true; }
}
public static string owncloudPrefix = "owncloud://";
public static string nextcloudPrefix = "nextcloud://";
public static string Owncloud2Webdav(string owncloudUrl, string prefix)
public static string Owncloud2Webdav(string owncloudUrl)
{
if (owncloudUrl.StartsWith(prefix))
string owncloudPrefix = "owncloud://";
if (owncloudUrl.StartsWith(owncloudPrefix))
{
owncloudUrl = owncloudUrl.Substring(prefix.Length);
owncloudUrl = owncloudUrl.Substring(owncloudPrefix.Length);
}
if (!owncloudUrl.Contains("://"))
owncloudUrl = "https://" + owncloudUrl;

View File

@@ -31,7 +31,7 @@
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<DefineConstants>TRACE;NoNet;EXCLUDE_JAVAFILESTORAGE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
@@ -53,7 +53,6 @@
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
<Reference Include="Xamarin.Android.Arch.Core.Common, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
@@ -106,21 +105,12 @@
<Compile Include="Io\AndroidContentStorage.cs" />
<Compile Include="Io\BuiltInFileStorage.cs" />
<Compile Include="Io\CachingFileStorage.cs" />
<Compile Include="Io\DropboxFileStorage.cs" />
<Compile Include="Io\DropboxFileStorageKeys.cs" />
<Compile Include="Io\FileDescription.cs" />
<Compile Include="Io\FileStorageSetupActivity.cs" />
<Compile Include="Io\FileStorageSetupInitiatorActivity.cs" />
<Compile Include="Io\GDriveFileStorage.cs" />
<Compile Include="Io\IFileStorage.cs" />
<Compile Include="Io\IoUtil.cs" />
<Compile Include="Io\JavaFileStorage.cs" />
<Compile Include="Io\NetFtpFileStorage.cs" />
<Compile Include="Io\OfflineSwitchableFileStorage.cs" />
<Compile Include="Io\PCloudFileStorage.cs" />
<Compile Include="Io\SftpFileStorage.cs" />
<Compile Include="Io\OneDriveFileStorage.cs" />
<Compile Include="Io\WebDavFileStorage.cs" />
<Compile Include="IProgressDialog.cs" />
<Compile Include="PreferenceKey.cs" />
<Compile Include="SelectStorageLocationActivityBase.cs" />
@@ -129,15 +119,15 @@
<Compile Include="database\edit\ActionOnFinish.cs" />
<Compile Include="database\edit\AddEntry.cs" />
<Compile Include="database\edit\AddGroup.cs" />
<Compile Include="database\edit\CreateDB.cs" />
<Compile Include="database\edit\CreateDb.cs" />
<Compile Include="database\edit\DeleteEntry.cs" />
<Compile Include="database\edit\DeleteGroup.cs" />
<Compile Include="database\edit\DeleteRunnable.cs" />
<Compile Include="database\edit\FileOnFinish.cs" />
<Compile Include="database\edit\LoadDB.cs" />
<Compile Include="database\edit\LoadDb.cs" />
<Compile Include="database\edit\OnFinish.cs" />
<Compile Include="database\edit\RunnableOnFinish.cs" />
<Compile Include="database\edit\SaveDB.cs" />
<Compile Include="database\edit\SaveDb.cs" />
<Compile Include="database\edit\SetPassword.cs" />
<Compile Include="database\edit\UpdateEntry.cs" />
<Compile Include="IKp2aApp.cs" />
@@ -156,14 +146,6 @@
<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>
</ProjectReference>
<ProjectReference Include="..\KeePassLib2Android\KeePassLib2Android.csproj">
<Project>{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}</Project>
<Name>KeePassLib2Android</Name>
@@ -172,10 +154,6 @@
<Project>{70D3844A-D9FA-4A64-B205-A84C6A822196}</Project>
<Name>KP2AKdbLibraryBinding</Name>
</ProjectReference>
<ProjectReference Include="..\netftpandroid\System.Net.FtpClient\System.Net.FtpClient.Android.csproj">
<Project>{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}</Project>
<Name>System.Net.FtpClient.Android</Name>
</ProjectReference>
<ProjectReference Include="..\TwofishCipher\TwofishCipher.csproj">
<Project>{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}</Project>
<Name>TwofishCipher</Name>

View File

@@ -30,12 +30,8 @@ namespace keepass2android
readonly IKp2aApp _app;
private readonly Handler _handler;
private string _message = "";
private string _submessage;
public String SubMessage => _submessage;
public String Message => _message;
public ProgressDialogStatusLogger() {
public ProgressDialogStatusLogger() {
}
@@ -60,7 +56,6 @@ namespace keepass2android
public void UpdateSubMessage(String submessage)
{
_submessage = submessage;
if (_app != null && _progressDialog != null && _handler != null)
{
_handler.Post(() =>

View File

@@ -25,107 +25,39 @@ namespace keepass2android
/// <summary>
/// Class to run a task while a progress dialog is shown
/// </summary>
public class ProgressTask
{
//for handling Activity recreation situations, we need access to the currently active task. It must hold that there is no more than one active task.
private static ProgressTask _currentTask = null;
public static void SetNewActiveActivity(Activity activeActivity)
{
if (_currentTask != null)
{
_currentTask.ActiveActivity = activeActivity;
}
}
public static void RemoveActiveActivity(Activity activity)
{
if ((_currentTask != null) && (_currentTask._activeActivity == activity))
_currentTask.ActiveActivity = null;
}
public Activity ActiveActivity
{
get { return _activeActivity; }
private set
{
_activeActivity = value;
if (_task != null)
_task.ActiveActivity = _activeActivity;
if (_activeActivity != null)
{
SetupProgressDialog(_app);
_progressDialog.Show();
}
}
}
private readonly Handler _handler;
public class ProgressTask {
private readonly Handler _handler;
private readonly RunnableOnFinish _task;
private IProgressDialog _progressDialog;
private readonly IProgressDialog _progressDialog;
private readonly IKp2aApp _app;
private Thread _thread;
private Activity _activeActivity;
private ProgressDialogStatusLogger _progressDialogStatusLogger;
public ProgressTask(IKp2aApp app, Activity activity, RunnableOnFinish task)
{
_activeActivity = activity;
public ProgressTask(IKp2aApp app, Context ctx, RunnableOnFinish task) {
_task = task;
_handler = app.UiThreadHandler;
_app = app;
SetupProgressDialog(app);
// Set code to run when this is finished
_task.OnFinishToRun = new AfterTask(activity, task.OnFinishToRun, _handler, this);
_task.SetStatusLogger(_progressDialogStatusLogger);
// Show process dialog
_progressDialog = app.CreateProgressDialog(ctx);
_progressDialog.SetTitle(_app.GetResourceString(UiStringKey.progress_title));
_progressDialog.SetMessage("Initializing...");
// Set code to run when this is finished
_task.OnFinishToRun = new AfterTask(task.OnFinishToRun, _handler, _progressDialog);
_task.SetStatusLogger(new ProgressDialogStatusLogger(_app, _handler, _progressDialog));
}
private void SetupProgressDialog(IKp2aApp app)
{
string currentMessage = "Initializing...";
string currentSubmessage = "";
if (_progressDialogStatusLogger != null)
{
currentMessage = _progressDialogStatusLogger.Message;
currentSubmessage = _progressDialogStatusLogger.SubMessage;
}
if (_progressDialog != null)
{
var pd = _progressDialog;
app.UiThreadHandler.Post(() =>
{
pd.Dismiss();
});
}
// Show process dialog
_progressDialog = app.CreateProgressDialog(_activeActivity);
_progressDialog.SetTitle(_app.GetResourceString(UiStringKey.progress_title));
_progressDialogStatusLogger = new ProgressDialogStatusLogger(_app, _handler, _progressDialog);
_progressDialogStatusLogger.UpdateMessage(currentMessage);
_progressDialogStatusLogger.UpdateSubMessage(currentSubmessage);
}
public void Run(bool allowOverwriteCurrentTask = false)
{
if ((!allowOverwriteCurrentTask) && (_currentTask != null))
throw new Exception("Cannot start another ProgressTask while ProgressTask is already running! " + _task.GetType().Name + "/" + _currentTask._task.GetType().Name);
_currentTask = this;
// Show process dialog
_progressDialog.Show();
public void Run() {
// Show process dialog
_progressDialog.Show();
// Start Thread to Run task
_thread = new Thread(_task.Run);
_thread.Start();
}
public void JoinWorkerThread()
@@ -134,11 +66,11 @@ namespace keepass2android
}
private class AfterTask : OnFinish {
readonly ProgressTask _progressTask;
readonly IProgressDialog _progressDialog;
public AfterTask (Activity activity, OnFinish finish, Handler handler, ProgressTask pt): base(activity, finish, handler)
public AfterTask (OnFinish finish, Handler handler, IProgressDialog pd): base(finish, handler)
{
_progressTask = pt;
_progressDialog = pd;
}
public override void Run() {
@@ -147,22 +79,17 @@ namespace keepass2android
if (Handler != null) //can be null in tests
{
// Remove the progress dialog
Handler.Post(delegate
{
_progressTask._progressDialog.Dismiss();
});
Handler.Post(delegate { _progressDialog.Dismiss(); });
}
else
{
_progressTask._progressDialog.Dismiss();
_progressDialog.Dismiss();
}
_currentTask = null;
}
}
}
}

View File

@@ -18,8 +18,8 @@ namespace keepass2android
private readonly IKp2aApp _app;
public CheckDatabaseForChanges(Activity context, IKp2aApp app, OnFinish finish)
: base(context, finish)
public CheckDatabaseForChanges(Context context, IKp2aApp app, OnFinish finish)
: base(finish)
{
_context = context;
_app = app;

View File

@@ -21,6 +21,7 @@ using System.IO;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.Text;
using Android.Content;
using Java.Lang;
using KeePassLib;
using KeePassLib.Keys;
@@ -217,7 +218,7 @@ namespace keepass2android
}
public void SaveData() {
public void SaveData(Context ctx) {
KpDatabase.UseFileTransactions = _app.GetBooleanPreference(PreferenceKey.UseFileTransactions);
using (IWriteTransaction trans = _app.GetFileStorage(Ioc).OpenWriteTransaction(Ioc, KpDatabase.UseFileTransactions))

View File

@@ -11,12 +11,12 @@ namespace keepass2android
{
public class SynchronizeCachedDatabase: RunnableOnFinish
{
private readonly Activity _context;
private readonly Context _context;
private readonly IKp2aApp _app;
private SaveDb _saveDb;
public SynchronizeCachedDatabase(Activity context, IKp2aApp app, OnFinish finish)
: base(context, finish)
public SynchronizeCachedDatabase(Context context, IKp2aApp app, OnFinish finish)
: base(finish)
{
_context = context;
_app = app;
@@ -59,7 +59,7 @@ namespace keepass2android
if (cachingFileStorage.HasLocalChanges(ioc))
{
//conflict! need to merge
_saveDb = new SaveDb(_context, _app, new ActionOnFinish(ActiveActivity, (success, result, activity) =>
_saveDb = new SaveDb(_context, _app, new ActionOnFinish((success, result) =>
{
if (!success)
{

View File

@@ -16,37 +16,41 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll.
*/
using System;
using Android.App;
using Android.OS;
namespace keepass2android
{
public class ActionOnFinish: OnFinish
{
public delegate void ActionToPerformOnFinsh(bool success, String message, Activity activeActivity);
public delegate void ActionToPerformOnFinsh(bool success, String message);
readonly ActionToPerformOnFinsh _actionToPerform;
public ActionOnFinish(Activity activity, ActionToPerformOnFinsh actionToPerform) : base(activity, null, null)
public ActionOnFinish(ActionToPerformOnFinsh actionToPerform) : base(null, null)
{
_actionToPerform = actionToPerform;
}
public ActionOnFinish(Activity activity, ActionToPerformOnFinsh actionToPerform, OnFinish finish) : base(activity, finish)
public ActionOnFinish(ActionToPerformOnFinsh actionToPerform, OnFinish finish) : base(finish)
{
_actionToPerform = actionToPerform;
}
public ActionOnFinish(ActionToPerformOnFinsh actionToPerform, Handler handler) : base(handler)
{
_actionToPerform = actionToPerform;
}
public override void Run()
{
if (Message == null)
Message = "";
if (Handler != null)
{
Handler.Post(() => {_actionToPerform(Success, Message, ActiveActivity);});
Handler.Post(() => {_actionToPerform(Success, Message);});
}
else
_actionToPerform(Success, Message, ActiveActivity);
_actionToPerform(Success, Message);
base.Run();
}
}

View File

@@ -15,7 +15,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using Android.App;
using Android.Content;
using KeePassLib;
@@ -30,20 +29,20 @@ namespace keepass2android
private readonly IKp2aApp _app;
private readonly PwEntry _entry;
private readonly PwGroup _parentGroup;
private readonly Activity _ctx;
private readonly Context _ctx;
public static AddEntry GetInstance(Activity ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish) {
public static AddEntry GetInstance(Context ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish) {
return new AddEntry(ctx, app, entry, parentGroup, finish);
}
protected AddEntry(Activity ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish):base(ctx, finish) {
protected AddEntry(Context ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish):base(finish) {
_ctx = ctx;
_parentGroup = parentGroup;
_app = app;
_entry = entry;
_onFinishToRun = new AfterAdd(ctx, app.GetDb(), entry, OnFinishToRun);
_onFinishToRun = new AfterAdd(app.GetDb(), entry, OnFinishToRun);
}
@@ -69,7 +68,7 @@ namespace keepass2android
private readonly Database _db;
private readonly PwEntry _entry;
public AfterAdd(Activity activity, Database db, PwEntry entry, OnFinish finish):base(activity, finish) {
public AfterAdd(Database db, PwEntry entry, OnFinish finish):base(finish) {
_db = db;
_entry = entry;

View File

@@ -16,7 +16,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/
using System;
using Android.App;
using Android.Content;
using KeePassLib;
@@ -35,16 +34,16 @@ namespace keepass2android
internal PwGroup Group;
internal PwGroup Parent;
protected bool DontSave;
readonly Activity _ctx;
readonly Context _ctx;
public static AddGroup GetInstance(Activity ctx, IKp2aApp app, string name, int iconid, PwUuid groupCustomIconId, PwGroup parent, OnFinish finish, bool dontSave) {
public static AddGroup GetInstance(Context ctx, IKp2aApp app, string name, int iconid, PwUuid groupCustomIconId, PwGroup parent, OnFinish finish, bool dontSave) {
return new AddGroup(ctx, app, name, iconid, groupCustomIconId, parent, finish, dontSave);
}
private AddGroup(Activity ctx, IKp2aApp app, String name, int iconid, PwUuid groupCustomIconId, PwGroup parent, OnFinish finish, bool dontSave)
: base(ctx, finish)
private AddGroup(Context ctx, IKp2aApp app, String name, int iconid, PwUuid groupCustomIconId, PwGroup parent, OnFinish finish, bool dontSave)
: base(finish)
{
_ctx = ctx;
_name = name;
@@ -54,7 +53,7 @@ namespace keepass2android
DontSave = dontSave;
_app = app;
_onFinishToRun = new AfterAdd(ctx, this, OnFinishToRun);
_onFinishToRun = new AfterAdd(this, OnFinishToRun);
}
@@ -77,7 +76,7 @@ namespace keepass2android
private class AfterAdd : OnFinish {
readonly AddGroup _addGroup;
public AfterAdd(Activity activity, AddGroup addGroup,OnFinish finish): base(activity, finish) {
public AfterAdd(AddGroup addGroup,OnFinish finish): base(finish) {
_addGroup = addGroup;
}

View File

@@ -18,7 +18,6 @@ This file is part of Keepass2Android, Copyright 2016 Philipp Crocoll. This file
using System;
using System.Collections.Generic;
using System.Linq;
using Android.App;
using Android.Content;
using KeePassLib;
using KeePassLib.Security;
@@ -129,10 +128,10 @@ namespace keepass2android
}
private readonly IKp2aApp _app;
private readonly Activity _ctx;
private readonly Context _ctx;
public AddTemplateEntries(Activity ctx, IKp2aApp app, OnFinish finish)
: base(ctx, finish)
public AddTemplateEntries(Context ctx, IKp2aApp app, OnFinish finish)
: base(finish)
{
_ctx = ctx;
_app = app;
@@ -359,7 +358,7 @@ namespace keepass2android
private readonly Database _db;
private readonly List<PwEntry> _entries;
public AfterAdd(Activity activity, Database db, List<PwEntry> entries, OnFinish finish):base(activity, finish) {
public AfterAdd(Database db, List<PwEntry> entries, OnFinish finish):base(finish) {
_db = db;
_entries = entries;

View File

@@ -16,7 +16,7 @@ namespace keepass2android.database.edit
{
public class CopyEntry: AddEntry
{
public CopyEntry(Activity ctx, IKp2aApp app, PwEntry entry, OnFinish finish)
public CopyEntry(Context ctx, IKp2aApp app, PwEntry entry, OnFinish finish)
: base(ctx, app, CreateCopy(entry, app), entry.ParentGroup, finish)
{
}

View File

@@ -16,7 +16,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/
using System.Collections.Generic;
using Android.App;
using Android.Content;
using KeePassLib;
using KeePassLib.Cryptography.KeyDerivation;
@@ -32,19 +31,19 @@ namespace keepass2android
private readonly IOConnectionInfo _ioc;
private readonly bool _dontSave;
private readonly Activity _ctx;
private readonly Context _ctx;
private readonly IKp2aApp _app;
private CompositeKey _key;
public CreateDb(IKp2aApp app, Activity ctx, IOConnectionInfo ioc, OnFinish finish, bool dontSave): base(ctx, finish) {
public CreateDb(IKp2aApp app, Context ctx, IOConnectionInfo ioc, OnFinish finish, bool dontSave): base(finish) {
_ctx = ctx;
_ioc = ioc;
_dontSave = dontSave;
_app = app;
}
public CreateDb(IKp2aApp app, Activity ctx, IOConnectionInfo ioc, OnFinish finish, bool dontSave, CompositeKey key)
: base(ctx, finish)
public CreateDb(IKp2aApp app, Context ctx, IOConnectionInfo ioc, OnFinish finish, bool dontSave, CompositeKey key)
: base(finish)
{
_ctx = ctx;
_ioc = ioc;

View File

@@ -17,7 +17,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
using System;
using System.Collections.Generic;
using Android.App;
using Android.Content;
using KeePassLib;
using KeePassLib.Interfaces;
@@ -29,8 +28,8 @@ namespace keepass2android
private readonly PwEntry _entry;
private UiStringKey _statusMessage;
public DeleteEntry(Activity activiy, IKp2aApp app, PwEntry entry, OnFinish finish):base(activiy, finish, app) {
Ctx = activiy;
public DeleteEntry(Context ctx, IKp2aApp app, PwEntry entry, OnFinish finish):base(finish, app) {
Ctx = ctx;
Db = app.GetDb();
_entry = entry;

View File

@@ -17,7 +17,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
using System;
using System.Collections.Generic;
using Android.App;
using Android.Content;
using KeePassLib;
@@ -29,10 +28,10 @@ namespace keepass2android
private PwGroup _group;
protected bool DontSave;
public DeleteGroup(Activity activity, IKp2aApp app, PwGroup group, OnFinish finish)
: base(activity, finish, app)
public DeleteGroup(Context ctx, IKp2aApp app, PwGroup group, OnFinish finish)
: base(finish, app)
{
SetMembers(activity, app, group, false);
SetMembers(ctx, app, group, false);
}
/*
public DeleteGroup(Context ctx, Database db, PwGroup group, Activity act, OnFinish finish, bool dontSave)
@@ -45,9 +44,9 @@ namespace keepass2android
SetMembers(ctx, db, group, null, dontSave);
}
*/
private void SetMembers(Activity activity, IKp2aApp app, PwGroup group, bool dontSave)
private void SetMembers(Context ctx, IKp2aApp app, PwGroup group, bool dontSave)
{
base.SetMembers(activity, app.GetDb());
base.SetMembers(ctx, app.GetDb());
_group = group;
DontSave = dontSave;

View File

@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using Android.App;
using Android.Content;
using KeePassLib;
using KeePassLib.Interfaces;
@@ -12,11 +11,11 @@ namespace keepass2android
private readonly List<IStructureItem> _elementsToDelete;
private readonly bool _canRecycle;
public DeleteMultipleItems(Activity activity, Database db, List<IStructureItem> elementsToDelete, OnFinish finish, IKp2aApp app)
: base(activity, finish, app)
public DeleteMultipleItems(Context ctx, Database db, List<IStructureItem> elementsToDelete, OnFinish finish, IKp2aApp app)
: base(finish, app)
{
_elementsToDelete = elementsToDelete;
SetMembers(activity, db);
SetMembers(ctx, db);
//determine once. The property is queried for each delete operation, but might return false
//after one entry/group is deleted (and thus in recycle bin and thus can't be recycled anymore)

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using Android.App;
using Android.Content;
using KeePassLib;
@@ -8,8 +7,8 @@ namespace keepass2android
{
public abstract class DeleteRunnable : RunnableOnFinish
{
protected DeleteRunnable(Activity activity, OnFinish finish, IKp2aApp app)
: base(activity, finish)
protected DeleteRunnable(OnFinish finish, IKp2aApp app)
: base(finish)
{
App = app;
}
@@ -18,11 +17,11 @@ namespace keepass2android
protected Database Db;
protected Activity Ctx;
protected Context Ctx;
protected void SetMembers(Activity activity, Database db)
protected void SetMembers(Context ctx, Database db)
{
Ctx = activity;
Ctx = ctx;
Db = db;
}
@@ -210,7 +209,7 @@ namespace keepass2android
Android.Util.Log.Debug("KP2A", "Calling PerformDelete..");
PerformDelete(touchedGroups, permanentlyDeletedGroups);
_onFinishToRun = new ActionOnFinish(ActiveActivity,(success, message, activity) =>
_onFinishToRun = new ActionOnFinish((success, message) =>
{
if (success)
{

View File

@@ -16,7 +16,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/
using System;
using Android.App;
using Android.Content;
using KeePassLib;
@@ -33,10 +32,10 @@ namespace keepass2android
private readonly PwIcon _iconId;
private readonly PwUuid _customIconId;
internal PwGroup Group;
readonly Activity _ctx;
readonly Context _ctx;
public EditGroup(Activity ctx, IKp2aApp app, String name, PwIcon iconid, PwUuid customIconId, PwGroup group, OnFinish finish)
: base(ctx, finish)
public EditGroup(Context ctx, IKp2aApp app, String name, PwIcon iconid, PwUuid customIconId, PwGroup group, OnFinish finish)
: base(finish)
{
_ctx = ctx;
_name = name;
@@ -45,7 +44,7 @@ namespace keepass2android
_customIconId = customIconId;
_app = app;
_onFinishToRun = new AfterEdit(ctx, this, OnFinishToRun);
_onFinishToRun = new AfterEdit(this, OnFinishToRun);
}
@@ -65,8 +64,8 @@ namespace keepass2android
private class AfterEdit : OnFinish {
readonly EditGroup _editGroup;
public AfterEdit(Activity ctx, EditGroup editGroup, OnFinish finish)
: base(ctx, finish)
public AfterEdit(EditGroup editGroup, OnFinish finish)
: base(finish)
{
_editGroup = editGroup;
}

View File

@@ -16,7 +16,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/
using System;
using Android.App;
namespace keepass2android
{
@@ -24,7 +23,7 @@ namespace keepass2android
public abstract class FileOnFinish : OnFinish {
private String _filename = "";
protected FileOnFinish(Activity activity, FileOnFinish finish):base(activity, finish) {
protected FileOnFinish(FileOnFinish finish):base(finish) {
}
public string Filename

View File

@@ -20,7 +20,6 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Android.App;
using KeePassLib;
using KeePassLib.Keys;
using KeePassLib.Serialization;
@@ -36,7 +35,7 @@ namespace keepass2android
private readonly bool _rememberKeyfile;
IDatabaseFormat _format;
public LoadDb(Activity activity, IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey, String keyfileOrProvider, OnFinish finish): base(activity, finish)
public LoadDb(IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey, String keyfileOrProvider, OnFinish finish): base(finish)
{
_app = app;
_ioc = ioc;

View File

@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using Android.App;
using Android.Content;
using KeePassLib;
using KeePassLib.Interfaces;
@@ -13,10 +12,10 @@ namespace keepass2android.database.edit
{
private readonly List<IStructureItem> _elementsToMove;
private readonly PwGroup _targetGroup;
private readonly Activity _ctx;
private readonly Context _ctx;
private readonly IKp2aApp _app;
public MoveElements(List<IStructureItem> elementsToMove, PwGroup targetGroup, Activity ctx, IKp2aApp app, OnFinish finish) : base(ctx, finish)
public MoveElements(List<IStructureItem> elementsToMove, PwGroup targetGroup, Context ctx, IKp2aApp app, OnFinish finish) : base(finish)
{
_elementsToMove = elementsToMove;
_targetGroup = targetGroup;
@@ -83,7 +82,7 @@ namespace keepass2android.database.edit
}
_onFinishToRun = new ActionOnFinish(ActiveActivity, (success, message, activity) =>
_onFinishToRun = new ActionOnFinish((success, message) =>
{
if (!success)
{ // Let's not bother recovering from a failure.

View File

@@ -16,7 +16,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
*/
using System;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Widget;
@@ -32,47 +31,27 @@ namespace keepass2android
protected OnFinish BaseOnFinish;
protected Handler Handler;
private ProgressDialogStatusLogger _statusLogger = new ProgressDialogStatusLogger(); //default: no logging but not null -> can be used whenever desired
private Activity _activeActivity;
public ProgressDialogStatusLogger StatusLogger
public ProgressDialogStatusLogger StatusLogger
{
get { return _statusLogger; }
set { _statusLogger = value; }
}
public Activity ActiveActivity
{
get { return _activeActivity; }
set
{
_activeActivity = value;
if (BaseOnFinish != null)
{
BaseOnFinish.ActiveActivity = value;
}
}
}
protected OnFinish(Activity activeActivity, Handler handler)
{
ActiveActivity = activeActivity;
protected OnFinish(Handler handler) {
BaseOnFinish = null;
Handler = handler;
}
protected OnFinish(Activity activeActivity, OnFinish finish, Handler handler)
{
ActiveActivity = activeActivity;
protected OnFinish(OnFinish finish, Handler handler) {
BaseOnFinish = finish;
Handler = handler;
}
protected OnFinish(Activity activeActivity, OnFinish finish)
{
ActiveActivity = activeActivity;
protected OnFinish(OnFinish finish) {
BaseOnFinish = finish;
Handler = null;
}
@@ -107,7 +86,7 @@ namespace keepass2android
{
if ( !String.IsNullOrEmpty(message) ) {
Kp2aLog.Log("OnFinish message: "+message);
Toast.MakeText(ctx ?? Application.Context, message, ToastLength.Long).Show();
Toast.MakeText(ctx, message, ToastLength.Long).Show();
}
}
}

View File

@@ -15,8 +15,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using Android.App;
using Android.Content;
namespace keepass2android
{
@@ -25,11 +23,8 @@ namespace keepass2android
protected OnFinish _onFinishToRun;
public ProgressDialogStatusLogger StatusLogger = new ProgressDialogStatusLogger(); //default: empty but not null
private Activity _activeActivity;
protected RunnableOnFinish(Activity activeActivity, OnFinish finish)
{
_activeActivity = activeActivity;
protected RunnableOnFinish(OnFinish finish) {
_onFinishToRun = finish;
}
@@ -39,18 +34,7 @@ namespace keepass2android
set { _onFinishToRun = value; }
}
public Activity ActiveActivity
{
get { return _activeActivity; }
set
{
_activeActivity = value;
if (_onFinishToRun != null)
_onFinishToRun.ActiveActivity = _activeActivity;
}
}
protected void Finish(bool result, String message, Exception exception = null) {
protected void Finish(bool result, String message, Exception exception = null) {
if ( OnFinishToRun != null ) {
OnFinishToRun.SetResult(result, message, exception);
OnFinishToRun.Run();
@@ -72,7 +56,7 @@ namespace keepass2android
StatusLogger = status;
}
public abstract void Run();
abstract public void Run();
}
}

View File

@@ -18,7 +18,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
using System;
using System.IO;
using System.Security.Cryptography;
using Android.App;
using Android.Content;
using Android.OS;
using Java.Lang;
@@ -43,8 +42,8 @@ namespace keepass2android
private readonly Context _ctx;
private Thread _workerThread;
public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish, bool dontSave)
: base(ctx, finish)
public SaveDb(Context ctx, IKp2aApp app, OnFinish finish, bool dontSave)
: base(finish)
{
_ctx = ctx;
_app = app;
@@ -59,8 +58,8 @@ namespace keepass2android
/// <param name="finish"></param>
/// <param name="dontSave"></param>
/// <param name="streamForOrigFile">Stream for reading the data from the (changed) original location</param>
public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish, bool dontSave, Stream streamForOrigFile)
: base(ctx, finish)
public SaveDb(Context ctx, IKp2aApp app, OnFinish finish, bool dontSave, Stream streamForOrigFile)
: base(finish)
{
_ctx = ctx;
_app = app;
@@ -68,8 +67,8 @@ namespace keepass2android
_streamForOrigFile = streamForOrigFile;
}
public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish)
: base(ctx, finish)
public SaveDb(Context ctx, IKp2aApp app, OnFinish finish)
: base(finish)
{
_ctx = ctx;
_app = app;
@@ -249,7 +248,7 @@ namespace keepass2android
private void PerformSaveWithoutCheck(IFileStorage fileStorage, IOConnectionInfo ioc)
{
StatusLogger.UpdateSubMessage("");
_app.GetDb().SaveData();
_app.GetDb().SaveData(_ctx);
_app.GetDb().LastFileVersion = fileStorage.GetCurrentFileVersionFast(ioc);
}

View File

@@ -15,7 +15,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using Android.App;
using Android.Content;
using KeePassLib;
using KeePassLib.Keys;
@@ -28,9 +27,9 @@ namespace keepass2android
private readonly String _keyfile;
private readonly IKp2aApp _app;
private readonly bool _dontSave;
private readonly Activity _ctx;
private readonly Context _ctx;
public SetPassword(Activity ctx, IKp2aApp app, String password, String keyfile, OnFinish finish): base(ctx, finish) {
public SetPassword(Context ctx, IKp2aApp app, String password, String keyfile, OnFinish finish): base(finish) {
_ctx = ctx;
_app = app;
_password = password;
@@ -38,8 +37,8 @@ namespace keepass2android
_dontSave = false;
}
public SetPassword(Activity ctx, IKp2aApp app, String password, String keyfile, OnFinish finish, bool dontSave)
: base(ctx, finish)
public SetPassword(Context ctx, IKp2aApp app, String password, String keyfile, OnFinish finish, bool dontSave)
: base(finish)
{
_ctx = ctx;
_app = app;
@@ -73,7 +72,7 @@ namespace keepass2android
pm.MasterKey = newKey;
// Save Database
_onFinishToRun = new AfterSave(ActiveActivity, previousKey, previousMasterKeyChanged, pm, OnFinishToRun);
_onFinishToRun = new AfterSave(previousKey, previousMasterKeyChanged, pm, OnFinishToRun);
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, _dontSave);
save.SetStatusLogger(StatusLogger);
save.Run();
@@ -84,7 +83,7 @@ namespace keepass2android
private readonly DateTime _previousKeyChanged;
private readonly PwDatabase _db;
public AfterSave(Activity activity, CompositeKey backup, DateTime previousKeyChanged, PwDatabase db, OnFinish finish): base(activity, finish) {
public AfterSave(CompositeKey backup, DateTime previousKeyChanged, PwDatabase db, OnFinish finish): base(finish) {
_previousKeyChanged = previousKeyChanged;
_backup = backup;
_db = db;

View File

@@ -15,7 +15,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using Android.App;
using Android.Content;
using KeePassLib;
@@ -24,13 +23,13 @@ namespace keepass2android
public class UpdateEntry : RunnableOnFinish {
private readonly IKp2aApp _app;
private readonly Activity _ctx;
private readonly Context _ctx;
public UpdateEntry(Activity ctx, IKp2aApp app, PwEntry oldE, PwEntry newE, OnFinish finish):base(ctx, finish) {
public UpdateEntry(Context ctx, IKp2aApp app, PwEntry oldE, PwEntry newE, OnFinish finish):base(finish) {
_ctx = ctx;
_app = app;
_onFinishToRun = new AfterUpdate(ctx, oldE, newE, app, finish);
_onFinishToRun = new AfterUpdate(oldE, newE, app, finish);
}
@@ -46,7 +45,7 @@ namespace keepass2android
private readonly PwEntry _updatedEntry;
private readonly IKp2aApp _app;
public AfterUpdate(Activity activity, PwEntry backup, PwEntry updatedEntry, IKp2aApp app, OnFinish finish):base(activity, finish) {
public AfterUpdate(PwEntry backup, PwEntry updatedEntry, IKp2aApp app, OnFinish finish):base(finish) {
_backup = backup;
_updatedEntry = updatedEntry;
_app = app;

View File

@@ -63,9 +63,6 @@
<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>
</Project>
<ItemGroup />
<Import Project="$(MSBuildExtensionsPath)\Novell\Xamarin.Android.Bindings.targets" />
</Project>

View File

@@ -1,48 +0,0 @@
Additions allow you to add arbitrary C# to the generated classes
before they are compiled. This can be helpful for providing convenience
methods or adding pure C# classes.
== Adding Methods to Generated Classes ==
Let's say the library being bound has a Rectangle class with a constructor
that takes an x and y position, and a width and length size. It will look like
this:
public partial class Rectangle
{
public Rectangle (int x, int y, int width, int height)
{
// JNI bindings
}
}
Imagine we want to add a constructor to this class that takes a Point and
Size structure instead of 4 ints. We can add a new file called Rectangle.cs
with a partial class containing our new method:
public partial class Rectangle
{
public Rectangle (Point location, Size size) :
this (location.X, location.Y, size.Width, size.Height)
{
}
}
At compile time, the additions class will be added to the generated class
and the final assembly will a Rectangle class with both constructors.
== Adding C# Classes ==
Another thing that can be done is adding fully C# managed classes to the
generated library. In the above example, let's assume that there isn't a
Point class available in Java or our library. The one we create doesn't need
to interact with Java, so we'll create it like a normal class in C#.
By adding a Point.cs file with this class, it will end up in the binding library:
public class Point
{
public int X { get; set; }
public int Y { get; set; }
}

View File

@@ -1,24 +0,0 @@
This directory is for Android .jars.
There are 2 types of jars that are supported:
== Input Jar ==
This is the jar that bindings should be generated for.
For example, if you were binding the Google Maps library, this would
be Google's "maps.jar".
Set the build action for these jars in the properties page to "InputJar".
== Reference Jars ==
These are jars that are referenced by the input jar. C# bindings will
not be created for these jars. These jars will be used to resolve
types used by the input jar.
NOTE: Do not add "android.jar" as a reference jar. It will be added automatically
based on the Target Framework selected.
Set the build action for these jars in the properties page to "ReferenceJar".

View File

@@ -1,90 +0,0 @@
<?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>
<ProjectGuid>{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}</ProjectGuid>
<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>
<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>0</WarningLevel>
<AndroidLinkMode>None</AndroidLinkMode>
</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>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseNoNet|AnyCPU'">
<OutputPath>bin\ReleaseNoNet\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
<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\pcloud-sdk-android-1.0.1.aar" />
</ItemGroup>
<ItemGroup>
<TransformFile Include="Transforms\Metadata.xml" />
<TransformFile Include="Transforms\EnumFields.xml" />
<TransformFile Include="Transforms\EnumMethods.xml" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\pcloud-sdk-java-core-1.0.1.jar" />
</ItemGroup>
</Project>

View File

@@ -1,30 +0,0 @@
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("PCloudBindings")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PCloudBindings")]
[assembly: AssemblyCopyright("Copyright © 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

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

View File

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

View File

@@ -1,10 +0,0 @@
<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.pcloud.sdk']" />
</metadata>

View File

@@ -1,20 +0,0 @@
#!/bin/bash
set -e
echo '*****************************************'
echo '********** Building Java parts **********'
echo '*****************************************'
./build-java.sh
echo '*****************************************'
echo '******** Building Xamarin parts *********'
echo '*****************************************'
./build-xamarin.sh
echo '*****************************************'
echo '************** Building APK *************'
echo '*****************************************'
./build-apk.sh
echo
echo 'Congratulations! You you can find the target APK in src/keepass2android/bin/Debug/.'

View File

@@ -1,8 +0,0 @@
#!/bin/bash
set -e
pushd ../keepass2android
xabuild keepass2android.csproj /t:SignAndroidPackage "$@"
popd

View File

@@ -1,18 +0,0 @@
#!/bin/bash
set -e
pushd ../java/
pushd JavaFileStorageTest-AS
./gradlew assemble
popd
pushd KP2ASoftkeyboard_AS
./gradlew assemble
popd
pushd Keepass2AndroidPluginSDK2
./gradlew assemble
popd
popd

View File

@@ -6,11 +6,11 @@ if exist "DropboxFileStorageKeys.cs" (
)
cd ..\..\keepass2android
call UseManifestDebug.bat
call UseManifestNoNet.bat
cd ..
call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86_amd64
msbuild KeePass.sln /target:keepass2android /p:BuildProjectReferences=true /p:Configuration="Debug" /p:Platform="Any CPU"
msbuild KeePass.sln /target:keepass2android /p:BuildProjectReferences=true /p:Configuration="Release" /p:Platform="Any CPU"
cd build-scripts

View File

@@ -1,25 +0,0 @@
#!/bin/bash
set -e
pushd ..
pushd Kp2aBusinessLogic/Io
if [ -f "DropboxFileStorageKeys.cs" ]
then
echo "DropboxFileStorageKeys.cs found."
else
cp DropboxFileStorageKeysDummy.cs DropboxFileStorageKeys.cs
fi
popd
pushd keepass2android
./UseManifestDebug.sh
popd
# call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86_amd64
xabuild KeePass.sln /target:keepass2android /p:BuildProjectReferences=true /p:Configuration="Debug" /p:Platform="Any CPU" "$@"
popd

View File

@@ -1,55 +0,0 @@
# How to build Keepass2Android
## Overview
Keepass2Android is a Mono for Android app. This means that you need Xamarin's Mono for Android to build it. However, it also uses several components written in Java, so there are also Android-Studio projects involved. To make things even worse, parts of the keyboard and kdb-library are written in native code.
The current build-scripts assume that the native libraries are already built (they are included in the repo).
To build KP2A from scratch, make sure that you have Xamarin's Mono for Android installed and also install Android Studio. Make sure that both point to the same Android SDK location.
## Prerequisites
- Install Xamarin.Android
- Fetch all submodules (`git submodule init && git submodule update`)
## Build
### On Windows
```bat
cd build-scripts
build-java.bat
build-xamarin.bat
```
build-java.bat will call gradlew for several Java modules. build-xamarin.bat will first make sure that you have all files at their place. (There is a "secret" file for Dropbox SDK keys which is not in the repo, this is replaced with a dummy file. There are also different Android Manifest files depending on the configuration which is selected by calling the appropriate script.)
**Notes:**
- For building the java parts, it is suggested to keep a short name (e.g. "c:\projects\keepass2android") for the root project directory. Otherwise the Windows path length limit might be hit when building.
- Before building the java parts, make sure you have set the ANDROID_HOME variable or create a local.properties file inside the directories with a gradlew file. It is recommended to use the same SDK location as that of the Xamarin build.
### On Linux
- Install [Mono](https://www.mono-project.com/)
- Install Xamarin.Android
- Option 1: Use the mono-project [CI builds](https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android-linux/lastSuccessfulBuild/Azure/)
- Option 2: [Build it from source](https://github.com/xamarin/xamarin-android/blob/master/Documentation/README.md#building-from-source)
- Setup your environment:
- Add `xabuild` to your path: `export PATH=/path/to/xamarin.android-oss/bin/Release/bin/:$PATH`
- Setup your `ANDROID_HOME` if it's not already: `export ANDROID_HOME=/path/to/android/`
- Alternatively, you can set your `ANDROID_SDK_PATH` and `ANDROID_NDK_PATH`.
- Build [jar2xml](https://github.com/xamarin/jar2xml) and copy `jar2xml.jar` to `/path/to/xamarin.android-oss/bin/Release/lib/xamarin.android/xbuild/Xamarin/Android/`
- Install [libzip](https://libzip.org/) for your distribution.
- Note: Xamarin seems to require `libzip4`, yet most distributions only ships `libzip5`. As a dirty workaround, it's possible to symlink `libzip.so.5` to `libzip.so.4`. Luckily, it appears to be working.
- `sudo ln -s /usr/lib/libzip.so.5 /usr/lib/libzip.so.4`
- Install NuGet dependencies:
- `cd src/ && nuget restore KeePass.sln`
- Build:
- Option 1: `cd build-scripts && ./build-all.sh`
- Option 2:
- Build the Java parts: `cd build-scripts/ && ./build-java.sh`
- Build the Xamarin parts: `./build-xamarin.sh`
- Build the signed APK: `./build-apk.sh`
- Enjoy:
- `adb install ../keepass2android/bin/Debug/keepass2android.keepass2android_debug-Signed.apk`

23
src/build.readme.txt Normal file
View File

@@ -0,0 +1,23 @@
How to build Keepass2Android
* Overview *
Keepass2Android is a Mono for Android app. This means that you need Xamarin's Mono for Android to build it. However, it also uses several components written in Java, so there are also Android-Studio projects involved. To make things even worse, parts of the keyboard and kdb-library are written in native code.
The current build-scripts assume that the native libraries are already built (they are included in the repo).
To build KP2A from scratch, make sure that you have Xamarin's Mono for Android installed and also install Android Studio. Make sure that both point to the same Android SDK location.
On Windows you can use
cd build-scripts
build-java.bat
build-xamarin.bat
build-java.bat will call gradlew for several Java modules. build-xamarin.bat will first make sure that you have all files at their place. (There is a "secret" file for Dropbox SDK keys which is not in the repo, this is replaced with a dummy file. There are also different Android Manifest files depending on the configuration which is selected by calling the appropriate script.)
* Notes *
- Please don't forget to update the git submodules before building.
- For building the java parts on Windows, it is suggested to keep a short name (e.g. "c:\projects\keepass2android") for the root project directory. Otherwise the Windows path length limit might be hit when building.
- Before building the java parts, make sure you have set the ANDROID_HOME variable or create a local.properties file inside the directories with a gradlew file. It is recommended to use the same SDK location as that of the Xamarin build.

View File

@@ -35,8 +35,6 @@ dependencies {
compile('com.onedrive.sdk:onedrive-sdk-android:1.2.0') {
transitive = false
}
compile 'com.pcloud.sdk:java-core:1.0.1'
compile 'com.pcloud.sdk:android:1.0.1'
compile 'com.google.code.gson:gson:2.3.1'
compile 'com.microsoft.services.msa:msa-auth:0.8.6'
compile 'com.microsoft.aad:adal:1.14.0'

View File

@@ -1,21 +1,15 @@
<?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"/>
<application>
<activity
android:name=".NotifSlave"
android:label="Keepass2Android"></activity>
</application>
</manifest>
</manifest>

View File

@@ -38,8 +38,6 @@ import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
public class GoogleDriveFileStorage extends JavaFileStorageBase {
@@ -312,8 +310,6 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
String driveId = path.getGDriveId();
logDebug("id"+driveId);
File file = driveService.files().get(driveId).execute();
if (file.getLabels().getTrashed())
throw new FileNotFoundException(path.getDisplayName() + " is trashed!");
logDebug("...done.");
return file;
}
@@ -784,7 +780,7 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
public void onRequestPermissionsResult(FileStorageSetupActivity setupAct, int requestCode, String[] permissions, int[] grantResults)
{
logDebug("onRequestPermissionsResult");
if (grantResults[0] == PERMISSION_GRANTED)
if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
logDebug("granted");
initFileStorage(setupAct);
@@ -856,10 +852,9 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
boolean allOk = true;
for (String s: permissions)
{
int permissionRes = act.checkSelfPermission(s);
logDebug("permissionRes "+s+"="+permissionRes);
if (permissionRes != PERMISSION_GRANTED)
allOk = false;
int permissionRes = act.checkSelfPermission(Manifest.permission.GET_ACCOUNTS);
logDebug("permissionRes="+permissionRes);
allOk = false;
}
if (!allOk)

View File

@@ -132,7 +132,7 @@ public class FileEntry {
public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception;
public String getCurrentFileVersionFast(String path) throws Exception;
public String getCurrentFileVersionFast(String path);
public InputStream openFileForRead(String path) throws Exception;
@@ -157,4 +157,4 @@ public class FileEntry {
public void onActivityResult(FileStorageSetupActivity activity, int requestCode, int resultCode, Intent data);
public void onRequestPermissionsResult(FileStorageSetupActivity activity, int requestCode, String[] permissions, int[] grantResults);
}
}

View File

@@ -1,169 +0,0 @@
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+"?");
}
}
}

View File

@@ -1,404 +0,0 @@
package keepass2android.javafilestorage;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.regex.Pattern;
import com.pcloud.sdk.ApiClient;
import com.pcloud.sdk.ApiError;
import com.pcloud.sdk.Authenticators;
import com.pcloud.sdk.AuthorizationActivity;
import com.pcloud.sdk.AuthorizationResult;
import com.pcloud.sdk.Call;
import com.pcloud.sdk.DataSource;
import com.pcloud.sdk.PCloudSdk;
import com.pcloud.sdk.RemoteEntry;
import com.pcloud.sdk.RemoteFile;
import com.pcloud.sdk.RemoteFolder;
/**
* FileStorage implementation for PCloud provider.
* https://www.pcloud.com/
*/
public class PCloudFileStorage extends JavaFileStorageBase
{
final static private int PCLOUD_AUTHORIZATION_REQUEST_CODE = 1001845497;
final static private String SHARED_PREF_NAME = "PCLOUD";
final static private String SHARED_PREF_AUTH_TOKEN = "AUTH_TOKEN";
private final Context ctx;
private ApiClient apiClient;
private String clientId;
public PCloudFileStorage(Context ctx, String clientId) {
this.ctx = ctx;
this.clientId = clientId;
this.apiClient = createApiClientFromSharedPrefs();
}
@Override
public boolean requiresSetup(String path) {
return true;
}
@Override
public void startSelectFile(FileStorageSetupInitiatorActivity activity, boolean isForSave, int requestCode) {
String path = getProtocolId() + "://";
activity.startSelectFileProcess(path, isForSave, requestCode);
}
@Override
public void prepareFileUsage(Context appContext, String path) throws Throwable {
if (!isConnected()) {
throw new UserInteractionRequiredException();
}
}
@Override
public void prepareFileUsage(FileStorageSetupInitiatorActivity activity, String path, int requestCode,
boolean alwaysReturnSuccess) {
if (this.isConnected()) {
Intent intent = new Intent();
intent.putExtra(EXTRA_PATH, path);
activity.onImmediateResult(requestCode, RESULT_FILEUSAGE_PREPARED, intent);
} else {
activity.startFileUsageProcess(path, requestCode, alwaysReturnSuccess);
}
}
@Override
public String getProtocolId() {
return "pcloud";
}
@Override
public String getDisplayName(String path) {
return path;
}
@Override
public String getFilename(String path) {
return path.substring(path.lastIndexOf("/") + 1);
}
@Override
public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception {
if (previousFileVersion == null || "".equals(previousFileVersion)) {
return false;
}
path = this.cleanPath(path);
RemoteFile remoteFile = this.getRemoteFileByPath(path);
return !remoteFile.hash().equals(previousFileVersion);
}
@Override
public String getCurrentFileVersionFast(String path) throws Exception {
path = this.cleanPath(path);
RemoteFile remoteFile = this.getRemoteFileByPath(path);
return remoteFile.hash();
}
@Override
public InputStream openFileForRead(String path) throws Exception {
path = this.cleanPath(path);
RemoteFile remoteFile = this.getRemoteFileByPath(path);
return remoteFile.byteStream();
}
@Override
public void uploadFile(String path, byte[] data, boolean writeTransactional) throws Exception {
path = this.cleanPath(path);
DataSource dataSource = DataSource.create(data);
String filename = path.substring(path.lastIndexOf("/") + 1);
String filePath = path.substring(0, path.lastIndexOf("/") + 1);
RemoteFolder remoteFolder = this.getRemoteFolderByPath(filePath);
try {
this.apiClient.createFile(remoteFolder, filename, dataSource).execute();
} catch (ApiError e) {
throw convertApiError(e);
}
}
@Override
public String createFolder(String parentPath, String newDirName) throws Exception {
String parentPathWithoutProtocol = this.cleanPath(parentPath);
RemoteFolder remoteFolder = this.getRemoteFolderByPath(parentPathWithoutProtocol);
try {
this.apiClient.createFolder(remoteFolder, newDirName).execute();
} catch (ApiError e) {
throw convertApiError(e);
}
return this.createFilePath(parentPath, newDirName);
}
@Override
public String createFilePath(String parentPath, String newFileName) throws Exception {
return (
this.getProtocolId() + "://" +
this.cleanPath(parentPath) +
("".equals(newFileName) ? "" : "/") +
newFileName
);
}
@Override
public List<FileEntry> listFiles(String parentPath) throws Exception {
parentPath = this.cleanPath(parentPath);
ArrayList<FileEntry> fileEntries = new ArrayList<>();
RemoteFolder remoteFolder = this.getRemoteFolderByPath(parentPath);
for (RemoteEntry remoteEntry : remoteFolder.children()) {
fileEntries.add(this.convertRemoteEntryToFileEntry(remoteEntry, parentPath));
}
return fileEntries;
}
@Override
public FileEntry getFileEntry(String path) throws Exception {
path = this.cleanPath(path);
RemoteEntry remoteEntry = this.getRemoteEntryByPath(path);
return this.convertRemoteEntryToFileEntry(
remoteEntry,
path.substring(0, path.lastIndexOf("/"))
);
}
@Override
public void delete(String path) throws Exception {
path = this.cleanPath(path);
RemoteEntry remoteEntry = this.getRemoteFileByPath(path);
try {
this.apiClient.delete(remoteEntry).execute();
} catch (ApiError e) {
throw convertApiError(e);
}
}
@Override
public void onCreate(FileStorageSetupActivity activity, Bundle savedInstanceState) {
}
@Override
public void onResume(FileStorageSetupActivity activity) {
if (activity.getProcessName().equals(PROCESS_NAME_SELECTFILE)) {
activity.getState().putString(EXTRA_PATH, activity.getPath());
}
if (this.isConnected()) {
finishActivityWithSuccess(activity);
} else if (!activity.getState().getBoolean("hasStartedAuth", false)) {
Activity castedActivity = (Activity)activity;
Intent authIntent = AuthorizationActivity.createIntent(castedActivity, this.clientId);
castedActivity.startActivityForResult(authIntent, PCLOUD_AUTHORIZATION_REQUEST_CODE);
activity.getState().putBoolean("hasStartedAuth", true);
}
}
@Override
public void onActivityResult(FileStorageSetupActivity activity, int requestCode, int resultCode, Intent data) {
if (requestCode == PCLOUD_AUTHORIZATION_REQUEST_CODE && data != null) {
activity.getState().putBoolean("hasStartedAuth", false);
AuthorizationResult result = (AuthorizationResult)(
data.getSerializableExtra(AuthorizationActivity.KEY_AUTHORIZATION_RESULT)
);
this.handleAuthResult(activity, result, data);
}
}
private void handleAuthResult(FileStorageSetupActivity activity, AuthorizationResult authorizationResult,
Intent data) {
if (authorizationResult == AuthorizationResult.ACCESS_GRANTED) {
String authToken = data.getStringExtra(AuthorizationActivity.KEY_ACCESS_TOKEN);
setAuthToken(authToken);
finishActivityWithSuccess(activity);
} else {
Activity castedActivity = (Activity)activity;
Intent resultData = new Intent();
resultData.putExtra(EXTRA_ERROR_MESSAGE, "Authentication failed.");
castedActivity.setResult(Activity.RESULT_CANCELED, resultData);
castedActivity.finish();
}
}
@Override
public void onStart(FileStorageSetupActivity activity) {
}
private ApiClient createApiClientFromSharedPrefs() {
SharedPreferences prefs = this.ctx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
String authToken = prefs.getString(SHARED_PREF_AUTH_TOKEN, null);
return this.createApiClient(authToken);
}
private ApiClient createApiClient(String authToken) {
if (authToken == null) {
return null;
}
return (
PCloudSdk.newClientBuilder()
.authenticator(Authenticators.newOAuthAuthenticator(authToken))
.create()
);
}
private boolean isConnected() {
return (this.apiClient != null);
}
private void clearAuthToken() {
this.apiClient = null;
SharedPreferences prefs = this.ctx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor edit = prefs.edit();
edit.clear();
edit.apply();
}
private void setAuthToken(String authToken) {
this.apiClient = this.createApiClient(authToken);
SharedPreferences prefs = this.ctx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor edit = prefs.edit();
edit.putString(SHARED_PREF_AUTH_TOKEN, authToken);
edit.apply();
}
private String cleanPath(String path) {
return (
"/" + path.replaceAll("^(" + Pattern.quote(this.getProtocolId()) + "://)?/*", "")
);
}
private RemoteFile getRemoteFileByPath(String path) throws Exception {
RemoteEntry remoteEntry = this.getRemoteEntryByPath(path);
try {
return remoteEntry.asFile();
} catch (IllegalStateException e) {
throw new FileNotFoundException(e.toString());
}
}
private RemoteFolder getRemoteFolderByPath(String path) throws Exception {
RemoteEntry remoteEntry = this.getRemoteEntryByPath(path);
try {
return remoteEntry.asFolder();
} catch (IllegalStateException e) {
throw new FileNotFoundException(e.toString());
}
}
private RemoteEntry getRemoteEntryByPath(String path) throws Exception {
Call<RemoteFolder> call = this.apiClient.listFolder(RemoteFolder.ROOT_FOLDER_ID, true);
RemoteFolder folder;
try {
folder = call.execute();
} catch (ApiError apiError) {
throw convertApiError(apiError);
}
if ("/".equals(path)) {
return folder;
}
String[] fileNames = path.substring(1).split("/");
RemoteFolder currentFolder = folder;
Iterator<String> fileNamesIterator = Arrays.asList(fileNames).iterator();
while (true) {
String fileName = fileNamesIterator.next();
Iterator<RemoteEntry> entryIterator = currentFolder.children().iterator();
while (true) {
RemoteEntry remoteEntry;
try {
remoteEntry = entryIterator.next();
} catch (NoSuchElementException e) {
throw new FileNotFoundException(e.toString());
}
if (currentFolder.folderId() == remoteEntry.parentFolderId() && fileName.equals(remoteEntry.name())) {
if (!fileNamesIterator.hasNext()) {
return remoteEntry;
}
try {
currentFolder = remoteEntry.asFolder();
} catch (IllegalStateException e) {
throw new FileNotFoundException(e.toString());
}
break;
}
}
}
}
private Exception convertApiError(ApiError e) {
String strErrorCode = String.valueOf(e.errorCode());
if (strErrorCode.startsWith("1") || "2000".equals(strErrorCode)) {
this.clearAuthToken();
return new UserInteractionRequiredException("Unlinked from PCloud! User must re-link.", e);
} else if (strErrorCode.startsWith("2")) {
return new FileNotFoundException(e.toString());
}
return e;
}
private FileEntry convertRemoteEntryToFileEntry(RemoteEntry remoteEntry, String parentPath) {
FileEntry fileEntry = new FileEntry();
fileEntry.canRead = true;
fileEntry.canWrite = true;
fileEntry.path = (
this.getProtocolId() + "://" +
("/".equals(parentPath) ? "" : parentPath) +
"/" + remoteEntry.name()
);
fileEntry.displayName = remoteEntry.name();
fileEntry.isDirectory = !remoteEntry.isFile();
fileEntry.lastModifiedTime = remoteEntry.lastModified().getTime();
if (remoteEntry.isFile()) {
fileEntry.sizeInBytes = remoteEntry.asFile().size();
}
return fileEntry;
}
}

View File

@@ -2,9 +2,7 @@ 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;
@@ -15,7 +13,6 @@ 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;
@@ -24,7 +21,6 @@ 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 {
@@ -39,10 +35,8 @@ public class SftpStorage extends JavaFileStorageBase {
public String localPath;
public int port;
}
Context _appContext;
public SftpStorage(Context appContext) {
_appContext = appContext;
public SftpStorage() {
}
@@ -324,29 +318,10 @@ 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,_appContext);
UserInfo ui = new SftpUserInfo(ci.password);
session.setUserInfo(ui);
session.setConfig("PreferredAuthentications", "publickey,password");
session.connect();
Channel channel = session.openChannel("sftp");
@@ -358,37 +333,6 @@ 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();

View File

@@ -1,119 +1,14 @@
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, Context appContext)
{
public SftpUserInfo(String password) {
_password = password;
_appContext = appContext;
}
@Override
@@ -140,15 +35,12 @@ public class SftpUserInfo implements UserInfo {
@Override
public boolean promptYesNo(String message) {
return (Boolean)dance("yesno", message);
//test with https://www.sftp.net/public-online-sftp-servers?
return true; //continue all operations without user action
}
@Override
public void showMessage(String message)
{
dance("message", message);
public void showMessage(String message) {
Log.d("KP2AJ", message);
}
}

View File

@@ -1,4 +0,0 @@
<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>

0
src/java/JavaFileStorage/gradlew vendored Executable file → Normal file
View File

View File

@@ -135,12 +135,7 @@ 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;
@@ -531,9 +526,9 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag
}
static JavaFileStorage createStorageToTest(Context ctx, Context appContext, boolean simulateRestart) {
storageToTest = new SftpStorage(ctx.getApplicationContext());
//storageToTest = new SftpStorage();
//storageToTest = new SkyDriveFileStorage("000000004010C234", appContext);
//storageToTest = new OneDriveStorage(appContext, "000000004010C234");
storageToTest = new OneDriveStorage(appContext, "000000004010C234");
//storageToTest = new GoogleDriveFileStorage();
/*storageToTest = new WebDavStorage(new ICertificateErrorHandler() {
@Override
@@ -667,20 +662,6 @@ 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)
@@ -688,30 +669,6 @@ 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")

View File

@@ -46,8 +46,7 @@
android:inputType="textPassword"
android:singleLine="true"
android:text=""
android:hint="@string/hint_pass"
android:importantForAccessibility="no" />
android:hint="@string/hint_pass" />
<TextView android:id="@+id/initial_dir"
android:layout_width="wrap_content"
@@ -63,9 +62,6 @@
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>

View File

@@ -33,7 +33,6 @@
android:inputType="textPassword"
android:singleLine="true"
android:text="$T3st17$"
android:hint="@string/hint_pass"
android:importantForAccessibility="no" />
android:hint="@string/hint_pass" />
</LinearLayout>

0
src/java/JavaFileStorageTest-AS/gradlew vendored Executable file → Normal file
View File

View File

@@ -18,9 +18,5 @@
android:name="android.accessibilityservice"
android:resource="@xml/accserviceconfig" />
</service-->
<activity android:excludeFromRecents="true"
android:taskAffinity=""
android:theme="@android:style/Theme.Dialog"
android:name=".Kp2aDialog"></activity>
</application>
</manifest>

View File

@@ -10,18 +10,20 @@ public class KeyboardData
public static List<StringForTyping> availableFields = new ArrayList<StringForTyping>();
public static String entryName;
public static String entryId;
public static int kp2aFieldIndex = 0;
public static boolean hasData()
{
return !TextUtils.isEmpty(entryId);
}
public static boolean bla2()
{
return !TextUtils.isEmpty(entryId);
}
public static void clear()
{
availableFields.clear();
entryName = entryId = "";
kp2aFieldIndex = 0;
}
}

View File

@@ -1,10 +1,6 @@
package keepass2android.kbbridge;
import java.util.ArrayList;
import java.util.HashMap;
import keepass2android.softkeyboard.IKeyboardService;
import keepass2android.softkeyboard.KP2AKeyboard;
public class KeyboardDataBuilder {
private ArrayList<StringForTyping> availableFields = new ArrayList<StringForTyping>();
@@ -20,8 +16,5 @@ public class KeyboardDataBuilder {
public void commit()
{
KeyboardData.availableFields = this.availableFields;
KeyboardData.kp2aFieldIndex = 0;
if (KP2AKeyboard.CurrentlyRunningService != null)
KP2AKeyboard.CurrentlyRunningService.onNewData();
}
}

View File

@@ -1,9 +0,0 @@
package keepass2android.softkeyboard;
import keepass2android.kbbridge.StringForTyping;
public interface IKeyboardService
{
void commitStringForTyping(StringForTyping stringForTyping);
void onNewData();
}

View File

@@ -17,7 +17,6 @@
package keepass2android.softkeyboard;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -28,26 +27,21 @@ import android.content.SharedPreferences.Editor;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.BitmapDrawable;
import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.Keyboard;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.os.Debug;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.text.ClipboardManager;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.View;
@@ -60,9 +54,7 @@ import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import keepass2android.kbbridge.KeyboardData;
import keepass2android.kbbridge.StringForTyping;
import keepass2android.softkeyboard.LatinIMEUtil.RingCharBuffer;
@@ -72,24 +64,18 @@ import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
/**
* Input method implementation for Qwerty'ish keyboard.
*/
public class KP2AKeyboard extends InputMethodService
implements LatinKeyboardBaseView.OnKeyboardActionListener,
IKeyboardService,
SharedPreferences.OnSharedPreferenceChangeListener {
public static IKeyboardService CurrentlyRunningService;
private static String get_KEEPASS2ANDROID_KEYBOARD_CLEARED(Context ctx)
{
return ctx.getPackageName()+".keyboard_cleared";
@@ -325,7 +311,6 @@ public class KP2AKeyboard extends InputMethodService
@Override
public void onCreate() {
CurrentlyRunningService = this;
LatinImeLogger.init(this);
KeyboardSwitcher.init(this);
super.onCreate();
@@ -345,8 +330,6 @@ public class KP2AKeyboard extends InputMethodService
}
mReCorrectionEnabled = prefs.getBoolean(PREF_RECORRECTION_ENABLED,
getResources().getBoolean(R.bool.default_recorrection_enabled));
Log.d("KP2AK","finding plugin dicts...");
PluginManager.getPluginDictionaries(getApplicationContext());
@@ -375,7 +358,7 @@ public class KP2AKeyboard extends InputMethodService
// register to receive ringer mode changes for silent mode
IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
registerReceiver(mSilentModeReceiver, filter);
registerReceiver(mReceiver, filter);
prefs.registerOnSharedPreferenceChangeListener(this);
@@ -484,14 +467,12 @@ public class KP2AKeyboard extends InputMethodService
if (mContactsDictionary != null) {
mContactsDictionary.close();
}*/
unregisterReceiver(mSilentModeReceiver);
unregisterReceiver(mReceiver);
unregisterReceiver(mPluginManager);
unregisterReceiver(mClearKeyboardReceiver);
LatinImeLogger.commit();
LatinImeLogger.onDestroy();
CurrentlyRunningService = null;
super.onDestroy();
}
@@ -521,7 +502,6 @@ public class KP2AKeyboard extends InputMethodService
mOrientation = conf.orientation;
reloadKeyboards();
}
updateKp2aKeyLabels();
mConfigurationChanging = true;
super.onConfigurationChanged(conf);
mConfigurationChanging = false;
@@ -546,7 +526,6 @@ public class KP2AKeyboard extends InputMethodService
mKeyboardSwitcher.setKeyboardMode(
KeyboardSwitcher.MODE_TEXT, 0);
}
updateKp2aKeyLabels();
return mKeyboardSwitcher.getInputView();
}
@@ -708,7 +687,6 @@ public class KP2AKeyboard extends InputMethodService
attribute.imeOptions);
}
}
updateKp2aKeyLabels();
}
private void updateShowKp2aMode() {
@@ -1087,7 +1065,6 @@ public class KP2AKeyboard extends InputMethodService
private void reloadKeyboards() {
mKeyboardSwitcher.setLanguageSwitcher(mLanguageSwitcher);
mKeyboardSwitcher.makeKeyboards(true);
updateKp2aKeyLabels();
}
private void commitTyped(InputConnection inputConnection) {
@@ -1277,9 +1254,6 @@ public class KP2AKeyboard extends InputMethodService
case LatinKeyboardView.KEYCODE_OPTIONS:
onOptionKeyPressed();
break;
case LatinKeyboardView.KEYCODE_KP2A_NEXTFIELDS:
onKp2aNextFieldsPressed();
break;
case LatinKeyboardView.KEYCODE_KP2A:
onKp2aKeyPressed();
break;
@@ -1368,96 +1342,28 @@ public class KP2AKeyboard extends InputMethodService
}
private void onKp2aPasswordKeyPressed() {
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));
commitStringForTyping(findStringForTyping("Password"));
}
private StringForTyping findStringForTyping(String key) {
for (StringForTyping s: keepass2android.kbbridge.KeyboardData.availableFields)
{
if (key.equals(s.key))
{
return s;
}
}
//found nothing: return empty struct:
return new StringForTyping();
}
private void onKp2aUserKeyPressed() {
commitStringForTyping(KeyboardData.availableFields.get(KeyboardData.kp2aFieldIndex));
commitStringForTyping(findStringForTyping("UserName"));
}
private void onKp2aNextFieldsPressed()
{
List<StringForTyping> availableFields = keepass2android.kbbridge.KeyboardData.availableFields;
if (KeyboardData.kp2aFieldIndex >= availableFields.size()-2)
{
KeyboardData.kp2aFieldIndex = 0;
}
else if (KeyboardData.kp2aFieldIndex == availableFields.size()-3)
{
KeyboardData.kp2aFieldIndex++;
}
else
KeyboardData.kp2aFieldIndex += 2;
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() {
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) {
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() {
private void onKp2aKeyPressed() {
if ((mKeyboardSwitcher.getKeyboardMode() == KeyboardSwitcher.MODE_KP2A)
|| (!mKp2aEnableSimpleKeyboard)
|| (!keepass2android.kbbridge.KeyboardData.hasData()))
@@ -1470,149 +1376,132 @@ public class KP2AKeyboard extends InputMethodService
setCandidatesViewShown(false);
}
private void showKp2aDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
String title = "Keepass2Android";
List<StringForTyping> availableFields = keepass2android.kbbridge.KeyboardData.availableFields;
final EditorInfo attribute = getCurrentInputEditorInfo();
Log.d("KP2AK", "hint: "+attribute.hintText);
Log.d("KP2AK", "field name: "+attribute.fieldName);
Log.d("KP2AK", "label: "+attribute.label);
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)
{
Log.d("KP2AK", entry.displayName);
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;
private void openOverlaySettings() {
final Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.e(TAG, e.getMessage());
}
}
if ((clientPackageName != null) && (clientPackageName != ""))
{
StringForTyping searchEntry = new StringForTyping();
try
{
searchEntry.key = searchEntry.displayName
= getString(R.string.open_entry_for_app, 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());
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;
searchEntry.key = searchEntry.displayName
= "Search entry for app";
}
searchEntry.value = "KP2ASPECIAL_SearchUrlTask";
items.add(searchEntry);
}
builder.setTitle(title);
Intent i = new Intent(this, Kp2aDialog.class);
i.putExtra("clientPackageName", clientPackageName);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
else
{
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) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
String title = "Keepass2Android";
List<StringForTyping> availableFields = keepass2android.kbbridge.KeyboardData.availableFields;
Log.d("KP2AK", "clicked item: " + items.get(item).key);
if (items.get(item).value.startsWith("KP2ASPECIAL")) {
//change entry
Log.d("KP2AK", "clicked item: " + items.get(item).value);
final EditorInfo attribute = getCurrentInputEditorInfo();
attribute.dump(new Printer() {
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);
}
}
@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());
}
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);
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();
}
dialog.show();
}
public void commitStringForTyping(StringForTyping theItem) {
private void commitStringForTyping(StringForTyping theItem) {
if ((mKp2aRememberAutoFill) && (!TextUtils.isEmpty(getCurrentInputEditorInfo().hintText)))
{
@@ -1628,17 +1517,12 @@ public class KP2AKeyboard extends InputMethodService
Log.d("KP2AK", "committing text for " + theItem.key);
commitKp2aString(theItem.value, getCurrentInputEditorInfo());
}
@Override
public void onNewData() {
updateKp2aKeyLabels();
}
public void onText(CharSequence text) {
public void onText(CharSequence text) {
InputConnection ic = getCurrentInputConnection();
if (ic == null) return;
if (text == null)
@@ -1937,7 +1821,6 @@ public class KP2AKeyboard extends InputMethodService
}
setCandidatesViewShown(true);
updateInputViewShown();
updateKp2aKeyLabels();
postUpdateSuggestions();
}
});
@@ -2475,26 +2358,13 @@ public class KP2AKeyboard extends InputMethodService
// receive ringer mode changes to detect silent mode
private BroadcastReceiver mSilentModeReceiver = new BroadcastReceiver() {
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateRingerMode();
}
};
private BroadcastReceiver mCommitForTypingReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
StringForTyping stringForTyping = new StringForTyping();
stringForTyping.key = intent.getStringExtra("key");
stringForTyping.value = intent.getStringExtra("value");
KP2AKeyboard.this.commitStringForTyping(stringForTyping);
}
};
// update flags for silent mode
private void updateRingerMode() {
if (mAudioManager == null) {

View File

@@ -1,129 +0,0 @@
package keepass2android.softkeyboard;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.util.Printer;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
import keepass2android.kbbridge.StringForTyping;
public class Kp2aDialog extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
setContentView(R.layout.activity_kp2a_dialog);
ListView listview = ((ListView)findViewById(R.id.mylist));
final String clientPackageName = getIntent().getStringExtra("clientPackageName");
final ArrayList<StringForTyping> items = new ArrayList<StringForTyping>();
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);
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);
}
String[] itemNames = new String[items.size()];
int i=0;
for (StringForTyping sft: items)
itemNames[i++] = sft.displayName;
listview.setAdapter(new ArrayAdapter<String>(this,
R.layout.kp2a_textview,
itemNames));
listview.setClickable(true);
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int item, long l) {
Log.d("KP2AK", "clicked item: " + items.get(item).key);
if (items.get(item).value.startsWith("KP2ASPECIAL")) {
//change entry
Log.d("KP2AK", "clicked item: " + items.get(item).value);
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);
KP2AKeyboard.CurrentlyRunningService.commitStringForTyping(theItem);
}
Kp2aDialog.this.finish();
}
});
findViewById(R.id.button_cancel).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Kp2aDialog.this.finish();
}
});
}
}

View File

@@ -43,7 +43,6 @@ public class LatinKeyboardView extends LatinKeyboardBaseView {
static final int KEYCODE_KP2A_ALPHA = -203;
static final int KEYCODE_KP2A_SWITCH = -204;
static final int KEYCODE_KP2A_LOCK = -205;
static final int KEYCODE_KP2A_NEXTFIELDS = -206;
private Keyboard mPhoneKeyboard;

View File

@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:padding="12dp">
<Button
android:id="@+id/button_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginTop="19dp"
android:text="@string/cancel" />
<ListView
android:id="@+id/mylist"
android:layout_above="@id/button_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
tools:context="keepass2android.softkeyboard.Kp2aDialog">
</ListView>
</RelativeLayout>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:paddingTop="6dip"
android:paddingBottom="6dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20sp" />

View File

@@ -8,7 +8,7 @@
<string name="kp2a_password">密码</string>
<string name="kp2a_prefs">输入凭据设置</string>
<string name="kp2a_auto_fill">自动填充已启用</string>
<string name="kp2a_auto_fill_summary">填充区域为空白、键盘有待输入条目、且有字段匹配填充区域的提示文本时,自动将其填入</string>
<string name="kp2a_auto_fill_summary">进入一个空白字段时自动填充文字,如果 Keepass2Android 是激活键盘,且有一个相匹配字段的提示文本</string>
<string name="kp2a_remember_auto_fill">记忆字段提示文本</string>
<string name="kp2a_remember_auto_fill_summary">如果通过手动选择 Keepass2Android 填充字段,请记住哪个字段在对应字段中输入。该字段是后来由其提示文本重新检测到。</string>
<string name="kp2a_simple_keyboard">简易键盘</string>

View File

@@ -35,7 +35,6 @@
<integer name="key_kp2a_alpha">-203</integer>
<integer name="key_kp2a_switch">-204</integer>
<integer name="key_kp2a_lock">-205</integer>
<integer name="key_kp2a_nextfields">-206</integer>
</resources>

View File

@@ -376,7 +376,6 @@
<!-- Title for Latin keyboard debug settings activity / dialog -->
<string name="english_ime_debug_settings" translatable="false">Android keyboard Debug settings</string>
<string name="prefs_debug_mode" translatable="false">Debug Mode</string>
<string name="kp2a_nextfields"><![CDATA[>]]></string>
</resources>

View File

@@ -12,37 +12,32 @@
<Key
android:codes="@integer/key_kp2a_alpha"
android:keyLabel="@string/label_alpha_key"
android:keyWidth="10%p"
android:keyWidth="12%p"
android:isModifier="true"
android:keyEdgeFlags="left" />
<Key
android:codes="@integer/key_kp2a_user"
android:keyLabel="@string/kp2a_user"
android:keyWidth="22%p"
android:keyWidth="25%p"
/>
<Key
android:codes="@integer/key_kp2a_pass"
android:keyLabel="@string/kp2a_password"
android:keyWidth="12%p"
android:keyWidth="15%p"
/>
<Key
android:codes="@integer/key_kp2a_nextfields"
android:keyLabel="@string/kp2a_nextfields"
android:keyWidth="8%p"
/>
<Key
android:codes="@integer/key_kp2a"
android:keyIcon="@drawable/sym_keyboard_kp2a"
android:iconPreview="@drawable/sym_keyboard_feedback_kp2a"
android:popupKeyboard="@xml/popup_kp2a"
android:keyWidth="10%p"
android:keyWidth="12%p"
android:isModifier="true" />
<Key
android:codes="@integer/key_delete"
android:keyIcon="@drawable/sym_keyboard_delete"
android:iconPreview="@drawable/sym_keyboard_feedback_delete"
android:keyWidth="10%p"
android:keyWidth="12%p"
android:isModifier="true"
android:isRepeatable="true"
/>

View File

@@ -12,37 +12,32 @@
<Key
android:codes="@integer/key_kp2a_alpha"
android:keyLabel="@string/label_alpha_key"
android:keyWidth="10%p"
android:keyWidth="12%p"
android:isModifier="true"
android:keyEdgeFlags="left" />
<Key
android:codes="@integer/key_kp2a_user"
android:keyLabel="@string/kp2a_user"
android:keyWidth="19%p"
android:keyWidth="20%p"
/>
<Key
android:codes="@integer/key_kp2a_pass"
android:keyLabel="@string/kp2a_password"
android:keyWidth="19%p"
android:keyWidth="20%p"
/>
<Key
android:codes="@integer/key_kp2a_nextfields"
android:keyLabel="@string/kp2a_nextfields"
android:keyWidth="8%p"
/>
<Key
android:codes="@integer/key_kp2a"
android:keyIcon="@drawable/sym_keyboard_kp2a"
android:iconPreview="@drawable/sym_keyboard_feedback_kp2a"
android:popupKeyboard="@xml/popup_kp2a"
android:keyWidth="10%p"
android:keyWidth="12%p"
android:isModifier="true" />
<Key
android:codes="@integer/key_delete"
android:keyIcon="@drawable/sym_keyboard_delete"
android:iconPreview="@drawable/sym_keyboard_feedback_delete"
android:keyWidth="10%p"
android:keyWidth="12%p"
android:isModifier="true"
android:isRepeatable="true"
/>

View File

@@ -12,37 +12,32 @@
<Key
android:codes="@integer/key_kp2a_alpha"
android:keyLabel="@string/label_alpha_key"
android:keyWidth="10%p"
android:keyWidth="12%p"
android:isModifier="true"
android:keyEdgeFlags="left" />
<Key
android:codes="@integer/key_kp2a_user"
android:keyLabel="@string/kp2a_user"
android:keyWidth="19%p"
/>
android:keyWidth="20%p"
/>
<Key
android:codes="@integer/key_kp2a_pass"
android:keyLabel="@string/kp2a_password"
android:keyWidth="19%p"
/>
<Key
android:codes="@integer/key_kp2a_nextfields"
android:keyLabel="@string/kp2a_nextfields"
android:keyWidth="8%p"
/>
android:keyWidth="20%p"
/>
<Key
android:codes="@integer/key_kp2a"
android:keyIcon="@drawable/sym_bkeyboard_kp2a"
android:iconPreview="@drawable/sym_keyboard_feedback_kp2a"
android:popupKeyboard="@xml/popup_kp2a"
android:keyWidth="10%p"
android:keyWidth="12%p"
android:isModifier="true" />
<Key
android:codes="@integer/key_delete"
android:keyIcon="@drawable/sym_bkeyboard_delete"
android:iconPreview="@drawable/sym_keyboard_feedback_delete"
android:keyWidth="10%p"
android:keyWidth="12%p"
android:isRepeatable="true"
/>
<Key

0
src/java/KP2ASoftkeyboard_AS/gradlew vendored Executable file → Normal file
View File

0
src/java/Keepass2AndroidPluginSDK2/gradlew vendored Executable file → Normal file
View File

View File

@@ -13,7 +13,7 @@
<string name="afc_cmd_grid_view">Ruudukkonäkymä</string>
<string name="afc_cmd_home">Etusivu</string>
<string name="afc_cmd_list_view">Luettelonäkymä</string>
<string name="afc_cmd_new_folder">Uusi kansio</string>
<string name="afc_cmd_new_folder">Uusi kansio&#8230;</string>
<string name="afc_cmd_select_all_files">Valitse kaikki tiedostot</string>
<string name="afc_cmd_select_all_folders">Valitse kaikki kansiot</string>
<string name="afc_cmd_sort">Lajittele&#8230;</string>
@@ -23,8 +23,8 @@
<string name="afc_hint_folder_name">kansion nimi</string>
<string name="afc_hint_save_as_filename">tiedostonimi</string>
<string name="afc_hint_search">haku</string>
<string name="afc_msg_app_doesnot_have_permission_to_create_files">Sovelluksella ei ole oikeutta luoda tiedostoja / kansioita</string>
<string name="afc_msg_app_doesnot_have_permission_to_delete_files">Sovelluksella ei ole oikeutta poistaa tiedostoja / kansioita</string>
<string name="afc_msg_app_doesnot_have_permission_to_create_files">Sovelluksella ei ole oikeutta luoda tiedostoja/kansioita</string>
<string name="afc_msg_app_doesnot_have_permission_to_delete_files">Sovelluksella ei ole oikeutta poistaa tiedostoja/kansioita</string>
<string name="afc_msg_cancelled">Peruutettu</string>
<string name="afc_msg_cannot_connect_to_file_provider_service">Ei voida yhdistää tiedoston tarjoavaan palveluun</string>
<string name="afc_msg_cannot_create_new_folder_here">Uutta kansiota ei voi luoda tänne</string>
@@ -46,7 +46,7 @@
<string name="afc_pmsg_max_file_count_allowed">...liikaa tiedostoja, maksimimäärä on %1$,d</string>
<string name="afc_pmsg_unknown_error">Tuntematon virhe: %1$s</string>
<string name="afc_root">Juuri</string>
<string name="afc_title_advanced_selection">Valitse</string>
<string name="afc_title_advanced_selection">Valitse...</string>
<string name="afc_title_confirmation">Vahvista</string>
<string name="afc_title_date">Pvm.</string>
<string name="afc_title_error">Virhe</string>

View File

@@ -22,12 +22,8 @@ namespace keepass2android
{
public class CancelDialog : Dialog {
protected readonly Activity _activity;
public CancelDialog(Activity activity): base(activity)
{
_activity = activity;
}
public CancelDialog(Context context): base(context) {
}
public bool Canceled { get; private set; }

View File

@@ -36,13 +36,14 @@ namespace keepass2android
var chalIntent = Activity.TryGetYubichallengeIntentOrPrompt(challenge64, true);
if (chalIntent == null)
{
Error = Activity.GetString(Resource.String.NoChallengeApp);
}
else
{
Activity.StartActivityForResult(chalIntent, _requestCode);
}
throw new Exception("YubiChallenge not installed.");
Activity.StartActivityForResult(chalIntent, _requestCode);
});
while ((Response == null) && (Error == null))

Some files were not shown because too many files have changed in this diff Show More