Compare commits

...

41 Commits

Author SHA1 Message Date
Philipp Crocoll
02073c01b6 change to behavior of Autofill: If domain and package are not "compatible" (i.e. package is a trusted web browser or later DAL verification succeeded), allow to insert the credentials for the domain (no longer the package), but ask the user if he trusts the app. 2020-07-06 21:08:15 +02:00
Philipp Crocoll
d14d287c3a improve keyboard activation 2020-06-29 19:45:40 +02:00
Philipp Crocoll
862083c0be only show Google Drive option if device has PlayServices available 2020-06-29 12:02:45 +02:00
Philipp Crocoll
f83e5dcc6e update FluentFTP, hoping to see improvements onn https://github.com/PhilippC/keepass2android/issues/1284 2020-06-15 11:31:44 +02:00
Philipp Crocoll
eeaa9f3280 code cleanup 2020-06-15 11:25:08 +02:00
Philipp Crocoll
1fad137c1e fix https://github.com/PhilippC/keepass2android/issues/1015 (bad error message when file not found) 2020-06-15 11:24:38 +02:00
Philipp Crocoll
b88bca35ab fix potential crash when an unknown scheme is entered while editing the URL of a recent file, fixes https://github.com/PhilippC/keepass2android/issues/1055 2020-06-14 20:16:36 +02:00
Philipp Crocoll
e9b9d0a781 fix crash when switching tasks while saving, should fix https://github.com/PhilippC/keepass2android/issues/719 2020-06-14 20:14:39 +02:00
Philipp Crocoll
d30c532a88 fix to password input behind view icon, fixes https://github.com/PhilippC/keepass2android/issues/370 2020-06-14 06:45:16 +02:00
Philipp Crocoll
b4dbc4bc08 improve display of database name/location in notifications, fixes https://github.com/PhilippC/keepass2android/issues/568 2020-06-14 06:29:03 +02:00
Philipp Crocoll
85d852cc54 fix https://github.com/PhilippC/keepass2android/issues/1282 (saving through autofill not working on Android 10 due to missing NewTask flag) 2020-06-13 20:36:46 +02:00
Philipp Crocoll
484a4732f8 fix https://github.com/PhilippC/keepass2android/issues/695 (missing fields on keyboard dialog) 2020-06-13 20:33:58 +02:00
Philipp Crocoll
0649de8cc6 changing the intent filter for ActionView, trying not to be too broad as before but hopefully still catching most intents for viewing kdbx files. Closes https://github.com/PhilippC/keepass2android/issues/816 and https://github.com/PhilippC/keepass2android/issues/157 2020-06-11 11:41:30 +02:00
Philipp Crocoll
69f8481cf1 small code cleanup 2020-06-11 07:27:38 +02:00
Philipp Crocoll
1625e5e3ac specify flag exclude from recents to fix https://github.com/PhilippC/keepass2android/issues/912 2020-06-11 07:27:23 +02:00
Philipp Crocoll
be1cc06a4b reuse WebDav client; forcing WebDav to use http1.1. This is a workaround to fix https://github.com/PhilippC/keepass2android/issues/747 2020-06-11 06:01:47 +02:00
Philipp Crocoll
adc45d8151 show nicer error messages 2020-06-10 21:52:35 +02:00
Philipp Crocoll
965a79f029 don't throw potential exception when checking if file is readonly 2020-05-30 19:48:02 +02:00
Philipp Crocoll
7c72f781a2 add empty file 2020-03-09 12:31:53 +01:00
Philipp Crocoll
b9a15471ef copy FTP data to memory stream to avoid issues when client is closed before reading is complete, closes #1094 2020-03-09 11:58:19 +01:00
Philipp Crocoll
e667f4e89c fix potential NullReferenceException 2020-03-09 11:52:40 +01:00
Philipp Crocoll
349f6c7c90 fix potential crash when opening from internal cache, closes #1179 2020-03-09 10:28:44 +01:00
Philipp Crocoll
e688639f47 Merge branch 'master' into Branch_e1416b9 2020-03-02 10:10:49 +01:00
Philipp Crocoll
8fbeb5c409 upgrading build tools and NuGet packages. switching to Xamarin's Biometric Bindings (even though this reverts from 1.0.1 to 1.0.0) because of build issues/incompatibilities 2020-03-02 10:07:55 +01:00
Philipp Crocoll
9d34dfe23e enable compatibility mode for autofill closes #290, closes #1061 2020-02-17 11:59:04 +01:00
Philipp Crocoll
01ea54932c allow to disable fingerprint unlock (in QuickUnlock mode) after three failed attempts, closes #16 2020-02-16 21:26:33 +01:00
Philipp Crocoll
ad0ac93bd3 add more logging to diagnose why keyboard is switched back sometimes 2020-02-16 05:28:54 +01:00
Philipp Crocoll
dc9d830d16 show username in search result, closes #546 2020-02-15 10:18:38 +01:00
Philipp Crocoll
cab797ee1e delete zh-rCN folder, is now in -zh, closes #651 2020-02-15 10:08:38 +01:00
Philipp Crocoll
e1416b984e Apply password font in EditText views, closes #404 2020-02-15 10:05:27 +01:00
Philipp Crocoll
ff95c32c2d Request focus before calling ShowInputMethod, closes #1132 2020-02-15 09:35:49 +01:00
Philipp Crocoll
2b2deb291a catch invalid dates, closes #868 2020-02-15 04:15:35 +01:00
Philipp Crocoll
e51999ea1f display notifications to allow copying TOTP to clipboard when autofilling, closes #1072 2020-02-15 03:55:43 +01:00
Philipp Crocoll
7ba17b8552 start implementing notifications when searching, e.g. for Autofill 2020-02-15 03:26:35 +01:00
Philipp Crocoll
406723fab0 manifest for 1.08-r1 2020-02-15 03:24:52 +01:00
Philipp Crocoll
e1ea3a1502 Merge branch 'master' of https://github.com/PhilippC/keepass2android 2020-02-13 21:35:02 +01:00
Philipp Crocoll
3f101c070d update to biometric-1.0.1 2020-02-13 21:34:10 +01:00
Philipp Crocoll
dd49cc9324 Merge branch 'master' of c:/ph/keepass2android 2020-02-10 11:00:59 +01:00
Philipp Crocoll
d607151734 changelog for 1.08-r0 2020-02-10 11:00:51 +01:00
Philipp Crocoll
9b780cb216 update version for 1.08-r0 2020-02-10 10:07:13 +01:00
Philipp Crocoll
bd4c01c630 add missing files, ignore some files 2020-02-10 10:06:59 +01:00
91 changed files with 4789 additions and 3968 deletions

1
.gitignore vendored
View File

@@ -169,3 +169,4 @@ src/java/Keepass2AndroidPluginSDK2/build/generated/mockable-Google-Inc.-Google-A
/src/java/KP2AKdbLibrary/app/build
/src/java/KP2ASoftkeyboard_AS/app/.cxx
/src/java/KP2ASoftkeyboard_AS/app/src/main/libs
/src/java/KP2AKdbLibrary/app/.cxx

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,70 +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>{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}</ProjectGuid>
<ProjectTypeGuids>{10368E6C-D01B-4462-8E8B-01FC667A7035};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TemplateGuid>{77efb91c-a7e9-4b0e-a7c5-31eeec3c6d46}</TemplateGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>BiometricBinding</RootNamespace>
<AssemblyName>BiometricBinding</AssemblyName>
<FileAlignment>512</FileAlignment>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
<AndroidClassParser>class-parse</AndroidClassParser>
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>portable</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>portable</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\biometric-1.0.0-rc02.aar" />
</ItemGroup>
<ItemGroup>
<TransformFile Include="Transforms\Metadata.xml" />
<TransformFile Include="Transforms\EnumFields.xml" />
<TransformFile Include="Transforms\EnumMethods.xml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.AndroidX.Fragment">
<Version>1.0.0-preview02</Version>
</PackageReference>
</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,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,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("BiometricBinding")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BiometricBinding")]
[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,9 +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']" />
-->
</metadata>

View File

@@ -27,8 +27,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamsungPass", "SamsungPass\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PCloudBindings", "PCloudBindings\PCloudBindings.csproj", "{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BiometricBinding", "BiometricBinding\BiometricBinding.csproj", "{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -297,30 +295,6 @@ Global
{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
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Win32.ActiveCfg = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Win32.Build.0 = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|x64.ActiveCfg = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|x64.Build.0 = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Any CPU.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Win32.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Win32.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|x64.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|x64.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Win32.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -23,7 +23,7 @@ using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using keepass2android;
#if !KeePassUAP
using System.Drawing;
#endif
@@ -872,8 +872,17 @@ namespace KeePassLib.Serialization
pb = pb8;
}
long lSec = MemUtil.BytesToInt64(pb);
return new DateTime(lSec * TimeSpan.TicksPerSecond, DateTimeKind.Utc);
}
try
{
return new DateTime(lSec * TimeSpan.TicksPerSecond, DateTimeKind.Utc);
}
catch (System.ArgumentOutOfRangeException e)
{
//files might contain bad data, e.g. see #868. Fall back to MinValue
Kp2aLog.Log("Failed to read date from file.");
return DateTime.MinValue;
}
}
else
{
string str = ReadString(xr);

View File

@@ -11,7 +11,7 @@ using KeePassLib.Keys;
using KeePassLib.Serialization;
using keepass2android.Io;
using KeePassLib.Interfaces;
#if !NoNet
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
using Keepass2android.Javafilestorage;
#endif
@@ -29,7 +29,7 @@ namespace keepass2android
}
/// <summary>
/// <summary>
/// Interface through which Activities and the logic layer can access some app specific functionalities and Application static data
/// </summary>
/// This also contains methods which are UI specific and should be replacable for testing.
@@ -123,7 +123,7 @@ namespace keepass2android
bool CheckForDuplicateUuids { get; }
#if !NoNet
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
ICertificateErrorHandler CertificateErrorHandler { get; }

View File

@@ -270,7 +270,7 @@ namespace keepass2android.Io
}
else return false;
}
else throw new Exception("couldn't move to first result element: " + (cursor == null) + uri.ToString());
else return false;
}
catch (Exception e)
{

View File

@@ -216,9 +216,12 @@ namespace keepass2android.Io
try
{
using (var cl = GetClient(ioc))
{
return cl.OpenRead(IocToLocalPath(ioc), FtpDataType.Binary, 0);
}
{
var memStream = new MemoryStream();
cl.OpenRead(IocToLocalPath(ioc), FtpDataType.Binary, 0).CopyTo(memStream);
memStream.Seek(0, SeekOrigin.Begin);
return memStream;
}
}
catch (FtpCommandException ex)
{

View File

@@ -9,14 +9,14 @@ using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
#if !NoNet
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
using Keepass2android.Javafilestorage;
#endif
using KeePassLib.Serialization;
namespace keepass2android.Io
{
#if !NoNet
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
public class WebDavFileStorage: JavaFileStorage
{
public WebDavFileStorage(IKp2aApp app) : base(new Keepass2android.Javafilestorage.WebDavStorage(app.CertificateErrorHandler), app)

View File

@@ -22,7 +22,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;EXCLUDE_TWOFISH;_EXCLUDE_KEYBOARD;_EXCLUDE_FILECHOOSER;_EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
<DefineConstants>DEBUG;_EXCLUDE_TWOFISH;_EXCLUDE_KEYBOARD;_EXCLUDE_FILECHOOSER;_EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidLinkMode>None</AndroidLinkMode>
@@ -129,6 +129,10 @@
<Compile Include="Utils\Spr\SprEngine.PickChars.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AndroidFileChooserBinding\AndroidFileChooserBinding.csproj">
<Project>{3c0f7fe5-639f-4422-a087-8b26cf862d1b}</Project>
<Name>AndroidFileChooserBinding</Name>
</ProjectReference>
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj">
<Project>{48574278-4779-4b3a-a9e4-9cf1bc285d0b}</Project>
<Name>JavaFileStorageBindings</Name>
@@ -141,6 +145,10 @@
<Project>{70D3844A-D9FA-4A64-B205-A84C6A822196}</Project>
<Name>KP2AKdbLibraryBinding</Name>
</ProjectReference>
<ProjectReference Include="..\PCloudBindings\PCloudBindings.csproj">
<Project>{2db80c77-d46f-4970-b967-e9ffa9b2ac2e}</Project>
<Name>PCloudBindings</Name>
</ProjectReference>
<ProjectReference Include="..\TwofishCipher\TwofishCipher.csproj">
<Project>{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}</Project>
<Name>TwofishCipher</Name>
@@ -154,118 +162,118 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentFTP">
<Version>27.1.3</Version>
<Version>31.3.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.Graph">
<Version>1.17.0</Version>
<Version>1.21.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.Graph.Auth">
<Version>1.0.0-preview.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.Identity.Client">
<Version>4.4.0</Version>
<Version>4.8.2</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Core.Common">
<Version>1.1.1.1</Version>
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Core.Runtime">
<Version>1.1.1.1</Version>
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.Common">
<Version>1.1.1.1</Version>
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.LiveData">
<Version>1.1.1.1</Version>
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.LiveData.Core">
<Version>1.1.1.1</Version>
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.Runtime">
<Version>1.1.1.1</Version>
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.ViewModel">
<Version>1.1.1.1</Version>
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Animated.Vector.Drawable">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Annotations">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.AsyncLayoutInflater">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Collections">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Compat">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CoordinaterLayout">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Core.UI">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Core.Utils">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CursorAdapter">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CustomTabs">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CustomView">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.DocumentFile">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.DrawerLayout">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Fragment">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Interpolator">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Loader">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.LocalBroadcastManager">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Media.Compat">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Print">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.SlidingPaneLayout">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.SwipeRefreshLayout">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v13">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v4">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.VersionedParcelable">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.ViewPager">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />

View File

@@ -49,6 +49,11 @@ namespace keepass2android
get { return _activeActivity; }
private set
{
if (_activeActivity != null && _activeActivity != _previouslyActiveActivity)
{
_previouslyActiveActivity = _activeActivity;
}
_activeActivity = value;
if (_task != null)
_task.ActiveActivity = _activeActivity;
@@ -60,12 +65,18 @@ namespace keepass2android
}
}
private readonly Handler _handler;
public Activity PreviouslyActiveActivity
{
get { return _previouslyActiveActivity; }
}
private readonly Handler _handler;
private readonly RunnableOnFinish _task;
private IProgressDialog _progressDialog;
private readonly IKp2aApp _app;
private Thread _thread;
private Activity _activeActivity;
private Activity _activeActivity, _previouslyActiveActivity;
private ProgressDialogStatusLogger _progressDialogStatusLogger;
public ProgressTask(IKp2aApp app, Activity activity, RunnableOnFinish task)

File diff suppressed because it is too large Load Diff

View File

@@ -88,6 +88,7 @@ namespace keepass2android
ReadOnlyReason_ReadOnlyKitKat,
ReadOnlyReason_LocalBackup,
Ok,
cancel
cancel,
FileNotFound
}
}

View File

@@ -36,8 +36,11 @@ namespace keepass2android
{
_actionToPerform = actionToPerform;
}
public override void Run()
//if set to true, the previously active active will be passed to ActionToPerformOnFinish instead null if no activity is on foreground
public bool AllowInactiveActivity { get; set; }
public override void Run()
{
if (Message == null)
Message = "";
@@ -46,7 +49,7 @@ namespace keepass2android
Handler.Post(() => {_actionToPerform(Success, Message, ActiveActivity);});
}
else
_actionToPerform(Success, Message, ActiveActivity);
_actionToPerform(Success, Message, AllowInactiveActivity ? (ActiveActivity ?? PreviouslyActiveActivity) : ActiveActivity);
base.Run();
}
}

View File

@@ -123,7 +123,7 @@ namespace keepass2android
{
if (!(e is InvalidCompositeKeyException))
Kp2aLog.LogUnexpectedError(e);
Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + e.Message, false, Exception);
Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + (e.Message ?? (e is FileNotFoundException ? _app.GetResourceString(UiStringKey.FileNotFound) : "")), false, Exception);
return;
}

View File

@@ -39,7 +39,7 @@ 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;
private Activity _activeActivity, _previouslyActiveActivity;
public ProgressDialogStatusLogger StatusLogger
@@ -53,7 +53,12 @@ namespace keepass2android
get { return _activeActivity; }
set
{
_activeActivity = value;
if (_activeActivity != null && _activeActivity != _previouslyActiveActivity)
{
_previouslyActiveActivity = _activeActivity;
}
_activeActivity = value;
if (BaseOnFinish != null)
{
BaseOnFinish.ActiveActivity = value;
@@ -61,8 +66,15 @@ namespace keepass2android
}
}
public Activity PreviouslyActiveActivity
{
get { return _previouslyActiveActivity; }
protected OnFinish(Activity activeActivity, Handler handler)
}
protected OnFinish(Activity activeActivity, Handler handler)
{
ActiveActivity = activeActivity;
BaseOnFinish = null;

View File

@@ -54,7 +54,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<LibraryProjectZip Include="..\java\Keepass2AndroidPluginSDK2\app\build\outputs\aar\Keepass2AndroidPluginSDK2-release.aar">
<LibraryProjectZip Include="..\java\Keepass2AndroidPluginSDK2\app\build\outputs\aar\app-release.aar">
<Link>Jars\Keepass2AndroidPluginSDK2-release.aar</Link>
</LibraryProjectZip>
<None Include="Jars\AboutJars.txt" />

View File

@@ -1,17 +1,17 @@
cd ..\java\JavaFileStorageTest-AS
call gradlew assemble
./gradlew assemble
cd ..\KP2ASoftkeyboard_AS
call gradlew assemble
./gradlew assemble
cd ..\Keepass2AndroidPluginSDK2
call gradlew assemble
./gradlew assemble
cd ..\KP2AKdbLibrary
call gradlew assemble
./gradlew assemble
cd ..\PluginQR
call gradlew assemble
./gradlew assemble
cd ..\..\build-scripts

View File

@@ -0,0 +1,17 @@
cd ..\java\JavaFileStorageTest-AS
./gradlew -q :app:dependencies > ../../build-scripts/dependencies-JavaFileStorageTest-AS.txt
cd ..\KP2ASoftkeyboard_AS
./gradlew -q :app:dependencies > ../../build-scripts/dependencies-KP2ASoftkeyboard_AS.txt
cd ..\Keepass2AndroidPluginSDK2
./gradlew -q :app:dependencies > ../../build-scripts/dependencies-Keepass2AndroidPluginSDK2.txt
cd ..\KP2AKdbLibrary
./gradlew -q :app:dependencies > ../../build-scripts/dependencies-KP2AKdbLibrary.txt
cd ..\PluginQR
./gradlew -q :app:dependencies > ../../build-scripts/dependencies-PluginQR.txt
cd ..\..\build-scripts

View File

@@ -1,11 +1,11 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 26
compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
minSdkVersion 15
targetSdkVersion 23
targetSdkVersion 28
}
buildTypes {
release {
@@ -26,6 +26,7 @@ NOTE: If you change dependencies here, don't forget to update the jar files in J
*/
dependencies {
compile 'com.android.support:appcompat-v7:28.0.0'
compile 'com.squareup.okhttp3:okhttp:4.2.2'
compile 'com.burgstaller:okhttp-digest:2.0'
compile 'com.google.android.gms:play-services:4.0.30'

View File

@@ -31,147 +31,7 @@ package com.jcraft.jsch.jgss;
import com.jcraft.jsch.JSchException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSManager;
import org.ietf.jgss.GSSName;
import org.ietf.jgss.MessageProp;
import org.ietf.jgss.Oid;
public class GSSContextKrb5 implements com.jcraft.jsch.GSSContext{
public class GSSContextKrb5 {
private static final String pUseSubjectCredsOnly =
"javax.security.auth.useSubjectCredsOnly";
private static String useSubjectCredsOnly =
getSystemProperty(pUseSubjectCredsOnly);
private GSSContext context=null;
public void create(String user, String host) throws JSchException{
try{
// RFC 1964
Oid krb5=new Oid("1.2.840.113554.1.2.2");
// Kerberos Principal Name Form
Oid principalName=new Oid("1.2.840.113554.1.2.2.1");
GSSManager mgr=GSSManager.getInstance();
GSSCredential crd=null;
/*
try{
GSSName _user=mgr.createName(user, principalName);
crd=mgr.createCredential(_user,
GSSCredential.DEFAULT_LIFETIME,
krb5,
GSSCredential.INITIATE_ONLY);
}
catch(GSSException crdex){
}
*/
String cname=host;
try{
cname=InetAddress.getByName(cname).getCanonicalHostName();
}
catch(UnknownHostException e){
}
GSSName _host=mgr.createName("host/"+cname, principalName);
context=mgr.createContext(_host,
krb5,
crd,
GSSContext.DEFAULT_LIFETIME);
// RFC4462 3.4. GSS-API Session
//
// When calling GSS_Init_sec_context(), the client MUST set
// integ_req_flag to "true" to request that per-message integrity
// protection be supported for this context. In addition,
// deleg_req_flag MAY be set to "true" to request access delegation, if
// requested by the user.
//
// Since the user authentication process by its nature authenticates
// only the client, the setting of mutual_req_flag is not needed for
// this process. This flag SHOULD be set to "false".
// TODO: OpenSSH's sshd does accepts 'false' for mutual_req_flag
//context.requestMutualAuth(false);
context.requestMutualAuth(true);
context.requestConf(true);
context.requestInteg(true); // for MIC
context.requestCredDeleg(true);
context.requestAnonymity(false);
return;
}
catch(GSSException ex){
throw new JSchException(ex.toString());
}
}
public boolean isEstablished(){
return context.isEstablished();
}
public byte[] init(byte[] token, int s, int l) throws JSchException {
try{
// Without setting "javax.security.auth.useSubjectCredsOnly" to "false",
// Sun's JVM for Un*x will show messages to stderr in
// processing context.initSecContext().
// This hack is not thread safe ;-<.
// If that property is explicitly given as "true" or "false",
// this hack must not be invoked.
if(useSubjectCredsOnly==null){
setSystemProperty(pUseSubjectCredsOnly, "false");
}
return context.initSecContext(token, 0, l);
}
catch(GSSException ex){
throw new JSchException(ex.toString());
}
catch(java.lang.SecurityException ex){
throw new JSchException(ex.toString());
}
finally{
if(useSubjectCredsOnly==null){
// By the default, it must be "true".
setSystemProperty(pUseSubjectCredsOnly, "true");
}
}
}
public byte[] getMIC(byte[] message, int s, int l){
try{
MessageProp prop = new MessageProp(0, true);
return context.getMIC(message, s, l, prop);
}
catch(GSSException ex){
return null;
}
}
public void dispose(){
try{
context.dispose();
}
catch(GSSException ex){
}
}
private static String getSystemProperty(String key){
try{ return System.getProperty(key); }
catch(Exception e){
// We are not allowed to get the System properties.
return null;
}
}
private static void setSystemProperty(String key, String value){
try{ System.setProperty(key, value); }
catch(Exception e){
// We are not allowed to set the System properties.
}
}
}

View File

@@ -5,6 +5,7 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import com.burgstaller.okhttp.AuthenticationCacheInterceptor;
@@ -44,6 +45,7 @@ import keepass2android.javafilestorage.webdav.PropfindXmlParser;
import keepass2android.javafilestorage.webdav.WebDavUtil;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
@@ -52,6 +54,7 @@ import okhttp3.internal.tls.OkHostnameVerifier;
public class WebDavStorage extends JavaFileStorageBase {
private final ICertificateErrorHandler mCertificateErrorHandler;
private Context appContext;
public WebDavStorage(ICertificateErrorHandler certificateErrorHandler)
{
@@ -125,9 +128,13 @@ public class WebDavStorage extends JavaFileStorageBase {
}
}
//client to be reused (connection pool/thread pool). We're building a custom client for each ConnectionInfo in getClient for actual usage
final OkHttpClient baseClient = new OkHttpClient();
private OkHttpClient getClient(ConnectionInfo ci) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpClient.Builder builder = baseClient.newBuilder();
final Map<String, CachingAuthenticator> authCache = new ConcurrentHashMap<>();
com.burgstaller.okhttp.digest.Credentials credentials = new com.burgstaller.okhttp.digest.Credentials(ci.username, ci.password);
@@ -169,6 +176,12 @@ public class WebDavStorage extends JavaFileStorageBase {
builder.writeTimeout(25, TimeUnit.SECONDS);
}
//OkHttp has issues with HTTP/2 (https://github.com/square/okhttp/issues/4964)
//An OkHttp developer suggested to use the same workaround as other apps:
// (https://github.com/PhilippC/keepass2android/issues/747#issuecomment-622946085)
//force HTTP1.1
builder.protocols(Arrays.asList(Protocol.HTTP_1_1));
OkHttpClient client = builder.build();
@@ -503,7 +516,7 @@ public class WebDavStorage extends JavaFileStorageBase {
@Override
public void prepareFileUsage(Context appContext, String path) {
//nothing to do
this.appContext = appContext;
}

View File

@@ -2,14 +2,19 @@
buildscript {
repositories {
jcenter()
maven {
url 'https://maven.google.com/'
name 'Google'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
classpath 'com.android.tools.build:gradle:3.3.2'
}
}
allprojects {
repositories {
jcenter()
google()
}
}

View File

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip

View File

@@ -1,13 +1,13 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
applicationId "com.crocoapps.javafilestoragetest"
minSdkVersion 21
targetSdkVersion 23
targetSdkVersion 28
versionCode 1
versionName "1.0"
multiDexEnabled true
@@ -28,7 +28,7 @@ android {
}
}
apply plugin: 'com.getkeepsafe.dexcount'
//apply plugin: 'com.getkeepsafe.dexcount'
dependencies {
compile project(':android-filechooser')

View File

@@ -8,7 +8,6 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
tools:replace="android:icon"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>

View File

@@ -9,11 +9,11 @@ buildscript {
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.android.tools.build:gradle:3.3.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.7.1'
//classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.7.1'
}
}

View File

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip

View File

@@ -0,0 +1,440 @@
package org.bouncycastle.asn1.util;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.BERConstructedOctetString;
import org.bouncycastle.asn1.BERConstructedSequence;
import org.bouncycastle.asn1.BERSequence;
import org.bouncycastle.asn1.BERSet;
import org.bouncycastle.asn1.BERTaggedObject;
import org.bouncycastle.asn1.DERBMPString;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERBoolean;
import org.bouncycastle.asn1.DERConstructedSequence;
import org.bouncycastle.asn1.DERConstructedSet;
import org.bouncycastle.asn1.DEREncodable;
import org.bouncycastle.asn1.DERGeneralizedTime;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERInteger;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DERObject;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERPrintableString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.DERT61String;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.DERUTCTime;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.DERUnknownTag;
import org.bouncycastle.asn1.DERVisibleString;
import org.bouncycastle.asn1.DERApplicationSpecific;
import org.bouncycastle.asn1.DERTags;
import org.bouncycastle.asn1.BERApplicationSpecific;
import org.bouncycastle.util.encoders.Hex;
import java.util.Enumeration;
import java.io.IOException;
public class ASN1Dump
{
private static final String TAB = " ";
private static final int SAMPLE_SIZE = 32;
/**
* dump a DER object as a formatted string with indentation
*
* @param obj the DERObject to be dumped out.
*/
static String _dumpAsString(
String indent,
boolean verbose,
DERObject obj)
{
String nl = System.getProperty("line.separator");
if (obj instanceof ASN1Sequence)
{
StringBuffer buf = new StringBuffer();
Enumeration e = ((ASN1Sequence)obj).getObjects();
String tab = indent + TAB;
buf.append(indent);
if (obj instanceof BERConstructedSequence)
{
buf.append("BER ConstructedSequence");
}
else if (obj instanceof DERConstructedSequence)
{
buf.append("DER ConstructedSequence");
}
else if (obj instanceof BERSequence)
{
buf.append("BER Sequence");
}
else if (obj instanceof DERSequence)
{
buf.append("DER Sequence");
}
else
{
buf.append("Sequence");
}
buf.append(nl);
while (e.hasMoreElements())
{
Object o = e.nextElement();
if (o == null || o.equals(new DERNull()))
{
buf.append(tab);
buf.append("NULL");
buf.append(nl);
}
else if (o instanceof DERObject)
{
buf.append(_dumpAsString(tab, verbose, (DERObject)o));
}
else
{
buf.append(_dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject()));
}
}
return buf.toString();
}
else if (obj instanceof DERTaggedObject)
{
StringBuffer buf = new StringBuffer();
String tab = indent + TAB;
buf.append(indent);
if (obj instanceof BERTaggedObject)
{
buf.append("BER Tagged [");
}
else
{
buf.append("Tagged [");
}
DERTaggedObject o = (DERTaggedObject)obj;
buf.append(Integer.toString(o.getTagNo()));
buf.append(']');
if (!o.isExplicit())
{
buf.append(" IMPLICIT ");
}
buf.append(nl);
if (o.isEmpty())
{
buf.append(tab);
buf.append("EMPTY");
buf.append(nl);
}
else
{
buf.append(_dumpAsString(tab, verbose, o.getObject()));
}
return buf.toString();
}
else if (obj instanceof DERConstructedSet)
{
StringBuffer buf = new StringBuffer();
Enumeration e = ((ASN1Set)obj).getObjects();
String tab = indent + TAB;
buf.append(indent);
buf.append("ConstructedSet");
buf.append(nl);
while (e.hasMoreElements())
{
Object o = e.nextElement();
if (o == null)
{
buf.append(tab);
buf.append("NULL");
buf.append(nl);
}
else if (o instanceof DERObject)
{
buf.append(_dumpAsString(tab, verbose, (DERObject)o));
}
else
{
buf.append(_dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject()));
}
}
return buf.toString();
}
else if (obj instanceof BERSet)
{
StringBuffer buf = new StringBuffer();
Enumeration e = ((ASN1Set)obj).getObjects();
String tab = indent + TAB;
buf.append(indent);
buf.append("BER Set");
buf.append(nl);
while (e.hasMoreElements())
{
Object o = e.nextElement();
if (o == null)
{
buf.append(tab);
buf.append("NULL");
buf.append(nl);
}
else if (o instanceof DERObject)
{
buf.append(_dumpAsString(tab, verbose, (DERObject)o));
}
else
{
buf.append(_dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject()));
}
}
return buf.toString();
}
else if (obj instanceof DERSet)
{
StringBuffer buf = new StringBuffer();
Enumeration e = ((ASN1Set)obj).getObjects();
String tab = indent + TAB;
buf.append(indent);
buf.append("DER Set");
buf.append(nl);
while (e.hasMoreElements())
{
Object o = e.nextElement();
if (o == null)
{
buf.append(tab);
buf.append("NULL");
buf.append(nl);
}
else if (o instanceof DERObject)
{
buf.append(_dumpAsString(tab, verbose, (DERObject)o));
}
else
{
buf.append(_dumpAsString(tab, verbose, ((DEREncodable)o).getDERObject()));
}
}
return buf.toString();
}
else if (obj instanceof DERObjectIdentifier)
{
return indent + "ObjectIdentifier(" + ((DERObjectIdentifier)obj).getId() + ")" + nl;
}
else if (obj instanceof DERBoolean)
{
return indent + "Boolean(" + ((DERBoolean)obj).isTrue() + ")" + nl;
}
else if (obj instanceof DERInteger)
{
return indent + "Integer(" + ((DERInteger)obj).getValue() + ")" + nl;
}
else if (obj instanceof BERConstructedOctetString)
{
ASN1OctetString oct = (ASN1OctetString)obj;
if (verbose)
{
return indent + "BER Constructed Octet String" + "[" + oct.getOctets().length + "] " + dumpBinaryDataAsString(indent, oct.getOctets()) + nl;
}
return indent + "BER Constructed Octet String" + "[" + oct.getOctets().length + "] " + nl;
}
else if (obj instanceof DEROctetString)
{
ASN1OctetString oct = (ASN1OctetString)obj;
if (verbose)
{
return indent + "DER Octet String" + "[" + oct.getOctets().length + "] " + dumpBinaryDataAsString(indent, oct.getOctets()) + nl;
}
return indent + "DER Octet String" + "[" + oct.getOctets().length + "] " + nl;
}
else if (obj instanceof DERBitString)
{
DERBitString bt = (DERBitString)obj;
if (verbose)
{
return indent + "DER Bit String" + "[" + bt.getBytes().length + ", " + bt.getPadBits() + "] " + dumpBinaryDataAsString(indent, bt.getBytes()) + nl;
}
return indent + "DER Bit String" + "[" + bt.getBytes().length + ", " + bt.getPadBits() + "] " + nl;
}
else if (obj instanceof DERIA5String)
{
return indent + "IA5String(" + ((DERIA5String)obj).getString() + ") " + nl;
}
else if (obj instanceof DERUTF8String)
{
return indent + "UTF8String(" + ((DERUTF8String)obj).getString() + ") " + nl;
}
else if (obj instanceof DERPrintableString)
{
return indent + "PrintableString(" + ((DERPrintableString)obj).getString() + ") " + nl;
}
else if (obj instanceof DERVisibleString)
{
return indent + "VisibleString(" + ((DERVisibleString)obj).getString() + ") " + nl;
}
else if (obj instanceof DERBMPString)
{
return indent + "BMPString(" + ((DERBMPString)obj).getString() + ") " + nl;
}
else if (obj instanceof DERT61String)
{
return indent + "T61String(" + ((DERT61String)obj).getString() + ") " + nl;
}
else if (obj instanceof DERUTCTime)
{
return indent + "UTCTime(" + ((DERUTCTime)obj).getTime() + ") " + nl;
}
else if (obj instanceof DERGeneralizedTime)
{
return indent + "GeneralizedTime(" + ((DERGeneralizedTime)obj).getTime() + ") " + nl;
}
else if (obj instanceof DERUnknownTag)
{
return indent + "Unknown " + Integer.toString(((DERUnknownTag)obj).getTag(), 16) + " " + new String(Hex.encode(((DERUnknownTag)obj).getData())) + nl;
}
else if (obj instanceof BERApplicationSpecific)
{
return outputApplicationSpecific("BER", indent, verbose, obj, nl);
}
else if (obj instanceof DERApplicationSpecific)
{
return outputApplicationSpecific("DER", indent, verbose, obj, nl);
}
else
{
return indent + obj.toString() + nl;
}
}
private static String outputApplicationSpecific(String type, String indent, boolean verbose, DERObject obj, String nl)
{
DERApplicationSpecific app = (DERApplicationSpecific)obj;
StringBuffer buf = new StringBuffer();
if (app.isConstructed())
{
try
{
ASN1Sequence s = ASN1Sequence.getInstance(app.getObject(DERTags.SEQUENCE));
buf.append(indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "]" + nl);
for (Enumeration e = s.getObjects(); e.hasMoreElements();)
{
buf.append(_dumpAsString(indent + TAB, verbose, (DERObject)e.nextElement()));
}
}
catch (IOException e)
{
buf.append(e);
}
return buf.toString();
}
return indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "] (" + new String(Hex.encode(app.getContents())) + ")" + nl;
}
/**
* dump out a DER object as a formatted string, in non-verbose mode.
*
* @param obj the DERObject to be dumped out.
* @return the resulting string.
*/
public static String dumpAsString(
Object obj)
{
return dumpAsString(obj, false);
}
/**
* Dump out the object as a string.
*
* @param obj the object to be dumped
* @param verbose if true, dump out the contents of octet and bit strings.
* @return the resulting string.
*/
public static String dumpAsString(
Object obj,
boolean verbose)
{
if (obj instanceof DERObject)
{
return _dumpAsString("", verbose, (DERObject)obj);
}
else if (obj instanceof DEREncodable)
{
return _dumpAsString("", verbose, ((DEREncodable)obj).getDERObject());
}
return "unknown object type " + obj.toString();
}
private static String dumpBinaryDataAsString(String indent, byte[] bytes)
{
String nl = System.getProperty("line.separator");
StringBuffer buf = new StringBuffer();
indent += TAB;
buf.append(nl);
for (int i = 0; i < bytes.length; i += SAMPLE_SIZE)
{
if (bytes.length - i > SAMPLE_SIZE)
{
buf.append(indent);
buf.append(new String(Hex.encode(bytes, i, SAMPLE_SIZE)));
buf.append(TAB);
buf.append(calculateAscString(bytes, i, SAMPLE_SIZE));
buf.append(nl);
}
else
{
buf.append(indent);
buf.append(new String(Hex.encode(bytes, i, bytes.length - i)));
for (int j = bytes.length - i; j != SAMPLE_SIZE; j++)
{
buf.append(" ");
}
buf.append(TAB);
buf.append(calculateAscString(bytes, i, bytes.length - i));
buf.append(nl);
}
}
return buf.toString();
}
private static String calculateAscString(byte[] bytes, int off, int len)
{
StringBuffer buf = new StringBuffer();
for (int i = off; i != off + len; i++)
{
if (bytes[i] >= ' ' && bytes[i] <= '~')
{
buf.append((char)bytes[i]);
}
}
return buf.toString();
}
}

View File

@@ -33,8 +33,10 @@ public class Kp2aDialog extends Activity {
final ArrayList<StringForTyping> items = new ArrayList<StringForTyping>();
List<StringForTyping> availableFields = keepass2android.kbbridge.KeyboardData.availableFields;
for (StringForTyping entry : availableFields) {
items.add(entry.clone());
}
StringForTyping openOrChangeEntry = new StringForTyping();
if (keepass2android.kbbridge.KeyboardData.entryName == null)

View File

@@ -0,0 +1,11 @@
//
// Created by Philipp on 21.09.2019.
//
#include <jni.h>
extern "C"
JNIEXPORT jstring JNICALL Java_keepass2android_softkeyboard_BinaryDictionary_getNativeString(
JNIEnv *env, jobject obj) {
return env->NewStringUTF("Hello World! From native code!");
}

View File

@@ -1,15 +1,30 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
maven {
url 'https://maven.google.com/'
name 'Google'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.1'
classpath 'com.android.tools.build:gradle:3.5.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
//classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.7.1'
}
}
allprojects {
repositories {
jcenter()
google()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip

View File

@@ -8,7 +8,7 @@ buildscript {
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.android.tools.build:gradle:3.3.2'
}
}
allprojects {

View File

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip

View File

@@ -3,9 +3,14 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<compositeConfiguration>
<compositeBuild compositeDefinitionSource="SCRIPT" />
</compositeConfiguration>
<option name="distributionType" value="LOCAL" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="C:\Program Files\Android\Android Studio1\gradle\gradle-2.14.1" />
<option name="resolveModulePerSourceSet" value="false" />
<option name="testRunner" value="PLATFORM" />
</GradleProjectSettings>
</option>
</component>

View File

@@ -5,36 +5,41 @@
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="4">
<list size="12">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="4" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="android.annotation.Nullable" />
<item index="7" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
<item index="10" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
<item index="11" class="java.lang.String" itemvalue="com.android.annotations.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<list size="11">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="5" class="java.lang.String" itemvalue="android.annotation.NonNull" />
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
<item index="10" class="java.lang.String" itemvalue="com.android.annotations.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

View File

@@ -3,6 +3,7 @@
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/android-filechooser-AS.iml" filepath="$PROJECT_DIR$/android-filechooser-AS.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
</modules>
</component>
</project>

View File

@@ -1,23 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="a8c99766-6088-49be-bc69-6d9a3515f47d" name="Default" comment="" />
<list default="true" id="a8c99766-6088-49be-bc69-6d9a3515f47d" name="Default" comment="">
<change beforePath="$PROJECT_DIR$/../../Kp2aBusinessLogic/Io/DropboxFileStorageKeysDummy.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/../../PluginSdkBinding/PluginSdkBinding.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/../../PluginSdkBinding/PluginSdkBinding.csproj" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../../build-scripts/build-java.bat" beforeDir="false" afterPath="$PROJECT_DIR$/../../build-scripts/build-java.bat" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../JavaFileStorage/app/src/main/java/com/jcraft/jsch/jgss/GSSContextKrb5.java" beforeDir="false" afterPath="$PROJECT_DIR$/../JavaFileStorage/app/src/main/java/com/jcraft/jsch/jgss/GSSContextKrb5.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../JavaFileStorage/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/../JavaFileStorage/build.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../JavaFileStorage/gradle/wrapper/gradle-wrapper.properties" beforeDir="false" afterPath="$PROJECT_DIR$/../JavaFileStorage/gradle/wrapper/gradle-wrapper.properties" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../JavaFileStorageTest-AS/app/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/../JavaFileStorageTest-AS/app/build.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../JavaFileStorageTest-AS/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/../JavaFileStorageTest-AS/build.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../JavaFileStorageTest-AS/gradle/wrapper/gradle-wrapper.properties" beforeDir="false" afterPath="$PROJECT_DIR$/../JavaFileStorageTest-AS/gradle/wrapper/gradle-wrapper.properties" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../Keepass2AndroidPluginSDK2/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/../Keepass2AndroidPluginSDK2/build.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../Keepass2AndroidPluginSDK2/gradle/wrapper/gradle-wrapper.properties" beforeDir="false" afterPath="$PROJECT_DIR$/../Keepass2AndroidPluginSDK2/gradle/wrapper/gradle-wrapper.properties" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/gradle.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/gradle.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/modules.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/modules.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android-filechooser-AS.iml" beforeDir="false" afterPath="$PROJECT_DIR$/android-filechooser-AS.iml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/app.iml" beforeDir="false" afterPath="$PROJECT_DIR$/app/app.iml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/app/build.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/AndroidManifest.xml" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/AndroidManifest.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/build.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gradle/wrapper/gradle-wrapper.properties" beforeDir="false" afterPath="$PROJECT_DIR$/gradle/wrapper/gradle-wrapper.properties" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../../keepass2android/keepass2android.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/../../keepass2android/keepass2android.csproj" afterDir="false" />
</list>
<ignored path="android-filechooser-AS.iws" />
<ignored path=".idea/workspace.xml" />
<ignored path="$PROJECT_DIR$/.gradle/" />
<ignored path="$PROJECT_DIR$/build/classes/" />
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="TRACKING_ENABLED" value="true" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="ChangesViewManager" flattened_view="true" show_ignored="false" />
<component name="CreatePatchCommitExecutor">
<option name="PATCH_PATH" value="" />
</component>
<component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
<component name="DefaultGradleProjectSettings">
<option name="testRunner" value="GRADLE" />
<option name="delegatedBuild" value="true" />
</component>
<component name="ExternalProjectsManager">
<system id="GRADLE">
<state>
@@ -30,162 +54,137 @@
</component>
<component name="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
<file leaf-file-name="build.gradle" pinned="false" current-in-tab="false">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<state relative-caret-position="119">
<caret line="7" column="5" selection-start-line="7" selection-start-column="5" selection-end-line="7" selection-end-column="5" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="Kp2aFileProvider.java" pinned="false" current-in-tab="false">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="38.444443">
<caret line="36" column="22" selection-start-line="36" selection-start-column="22" selection-end-line="36" selection-end-column="22" />
<folding>
<element signature="imports" expanded="false" />
<element signature="e#18771#18772#0" expanded="false" />
<element signature="e#18809#18810#0" expanded="false" />
<element signature="e#18861#18862#0" expanded="false" />
<element signature="e#18902#18903#0" expanded="false" />
</folding>
<state relative-caret-position="221">
<caret line="36" selection-start-line="36" selection-end-line="36" />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="Kp2aFileChooserBridge.java" pinned="false" current-in-tab="true">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileChooserBridge.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.4228395">
<caret line="11" column="68" selection-start-line="11" selection-start-column="68" selection-end-line="11" selection-end-column="68" />
<folding />
<state relative-caret-position="357">
<caret line="25" selection-start-line="25" selection-end-line="25" />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="build.gradle" pinned="false" current-in-tab="false">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="204">
<caret line="12" column="11" selection-start-line="12" selection-start-column="11" selection-end-line="12" selection-end-column="11" />
</state>
</provider>
<provider editor-type-id="android-manifest" />
</entry>
</file>
<file pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/app/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="16" column="5" selection-start-line="16" selection-start-column="5" selection-end-line="16" selection-end-column="5" />
<folding />
<state relative-caret-position="153">
<caret line="9" column="5" selection-start-line="9" selection-start-column="5" selection-end-line="9" selection-end-column="5" />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="local.properties" pinned="false" current-in-tab="false">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/app/src/main/java/group/pals/android/lib/ui/filechooser/FileChooserActivity.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="208">
<caret line="23" column="24" selection-start-line="23" selection-start-column="24" selection-end-line="23" selection-end-column="24" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/local.properties">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
<provider selected="true" editor-type-id="text-editor" />
</entry>
</file>
<file leaf-file-name="gradle.properties" pinned="false" current-in-tab="false">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/gradle.properties">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
<provider selected="true" editor-type-id="text-editor" />
</entry>
</file>
<file leaf-file-name="settings.gradle" pinned="false" current-in-tab="false">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/settings.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
<provider selected="true" editor-type-id="text-editor" />
</entry>
</file>
</leaf>
</component>
<component name="GradleLocalSettings">
<option name="externalProjectsViewState">
<projects_view />
</option>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/../../.." />
</component>
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/app/build.gradle" />
<option value="$PROJECT_DIR$/gradle.properties" />
<option value="$PROJECT_DIR$/build.gradle" />
<option value="$PROJECT_DIR$/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileChooserBridge.java" />
<option value="$PROJECT_DIR$/app/src/main/AndroidManifest.xml" />
<option value="$PROJECT_DIR$/app/build.gradle" />
</list>
</option>
</component>
<component name="ProjectFrameBounds">
<component name="ProjectFrameBounds" extendedState="6">
<option name="x" value="-8" />
<option name="y" value="-8" />
<option name="width" value="1382" />
<option name="height" value="744" />
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<component name="ProjectView">
<navigator currentView="Scope" currentSubView="Project Files" proportions="" version="1">
<flattenPackages />
<showMembers />
<showModules />
<showLibraryContents />
<hideEmptyPackages />
<abbreviatePackageNames />
<autoscrollToSource />
<autoscrollFromSource />
<sortByType />
<manualOrder />
<navigator currentView="ProjectPane" proportions="" version="1">
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="ProjectPane" />
<pane id="AndroidView">
<subPane>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="android-filechooser-AS" />
<option name="myItemType" value="com.android.tools.idea.navigator.nodes.AndroidViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="Gradle Scripts" />
<option name="myItemType" value="com.android.tools.idea.navigator.nodes.AndroidBuildScriptsGroupNode" />
</PATH_ELEMENT>
</PATH>
</subPane>
</pane>
<pane id="Scratches" />
<pane id="Scope">
<subPane subId="Project Files">
<PATH>
<PATH_ELEMENT USER_OBJECT="Root">
<option name="myItemId" value="" />
<option name="myItemType" value="" />
</PATH_ELEMENT>
</PATH>
</subPane>
</pane>
<pane id="Scope" />
<pane id="PackagesPane" />
<pane id="AndroidView" />
<pane id="ProjectPane">
<subPane>
<expand>
<path>
<item name="android-filechooser-AS" type="b2602c69:ProjectViewProjectNode" />
<item name="android-filechooser-AS" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
</path>
</expand>
<select />
</subPane>
</pane>
</panes>
</component>
<component name="PropertiesComponent">
<property name="SHARE_PROJECT_CONFIGURATION_FILES" value="true" />
<property name="android.project.structure.last.selected" value="android-filechooser-AS" />
<property name="android.project.structure.proportion" value="0.15" />
<property name="last_opened_file_path" value="$PROJECT_DIR$/../JavaFileStorageTest-AS" />
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="RunManager">
<configuration default="true" type="AndroidRunConfigurationType" factoryName="Android Application">
@@ -201,7 +200,7 @@
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="true" />
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
<option name="FORCE_STOP_RUNNING_APP" value="true" />
<option name="DEBUGGER_TYPE" value="Java" />
<option name="DEBUGGER_TYPE" value="Auto" />
<option name="USE_LAST_SELECTED_DEVICE" value="false" />
<option name="PREFERRED_AVD" value="" />
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="-1" />
@@ -236,7 +235,7 @@
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="true" />
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
<option name="FORCE_STOP_RUNNING_APP" value="true" />
<option name="DEBUGGER_TYPE" value="Java" />
<option name="DEBUGGER_TYPE" value="Auto" />
<option name="USE_LAST_SELECTED_DEVICE" value="false" />
<option name="PREFERRED_AVD" value="" />
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="-1" />
@@ -255,42 +254,6 @@
</Profilers>
<method />
</configuration>
<configuration default="true" type="Application" factoryName="Application">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<option name="MAIN_CLASS_NAME" />
<option name="VM_PARAMETERS" />
<option name="PROGRAM_PARAMETERS" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="ENABLE_SWING_INSPECTOR" value="false" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<module name="" />
<envs />
<method />
</configuration>
<configuration default="true" type="JUnit" factoryName="JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" />
<option name="MAIN_CLASS_NAME" />
<option name="METHOD_NAME" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" />
<option name="WORKING_DIRECTORY" value="$MODULE_DIR$" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<envs />
<patterns />
<method />
</configuration>
<configuration default="true" type="JUnitTestDiscovery" factoryName="JUnit Test Discovery" changeList="All">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="" />
@@ -312,61 +275,25 @@
<patterns />
<method />
</configuration>
<configuration default="true" type="JarApplication" factoryName="JAR Application">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<envs />
<method />
</configuration>
<configuration default="true" type="Java Scratch" factoryName="Java Scratch">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<option name="SCRATCH_FILE_ID" value="0" />
<option name="MAIN_CLASS_NAME" />
<option name="VM_PARAMETERS" />
<option name="PROGRAM_PARAMETERS" />
<option name="WORKING_DIRECTORY" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="ENABLE_SWING_INSPECTOR" value="false" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<module name="" />
<envs />
<method />
</configuration>
<configuration default="true" type="Remote" factoryName="Remote">
<option name="USE_SOCKET_TRANSPORT" value="true" />
<option name="SERVER_MODE" value="false" />
<option name="SHMEM_ADDRESS" value="javadebug" />
<option name="HOST" value="localhost" />
<option name="PORT" value="5005" />
<method />
</configuration>
<configuration default="true" type="TestNG" factoryName="TestNG">
<configuration default="true" type="JUnit" factoryName="JUnit">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="SUITE_NAME" />
<option name="PACKAGE_NAME" />
<option name="MAIN_CLASS_NAME" />
<option name="METHOD_NAME" />
<option name="GROUP_NAME" />
<option name="TEST_OBJECT" value="CLASS" />
<option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" />
<option name="WORKING_DIRECTORY" value="$MODULE_DIR$" />
<option name="OUTPUT_DIRECTORY" />
<option name="ANNOTATION_TYPE" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<option name="USE_DEFAULT_REPORTERS" value="false" />
<option name="PROPERTIES_FILE" />
<envs />
<properties />
<listeners />
<patterns />
<method />
</configuration>
<configuration default="true" type="TestNGTestDiscovery" factoryName="TestNG Test Discovery" changeList="All">
@@ -397,20 +324,38 @@
<listeners />
<method />
</configuration>
<configuration name="&lt;template&gt;" type="Applet" default="true" selected="false">
<option name="MAIN_CLASS_NAME" />
<option name="HTML_FILE_NAME" />
<option name="HTML_USED" value="false" />
<option name="WIDTH" value="400" />
<option name="HEIGHT" value="300" />
<option name="POLICY_FILE" value="$APPLICATION_HOME_DIR$/bin/appletviewer.policy" />
<option name="VM_PARAMETERS" />
</configuration>
<configuration name="&lt;template&gt;" type="#org.jetbrains.idea.devkit.run.PluginConfigurationType" default="true" selected="false">
<option name="VM_PARAMETERS" value="-Xmx512m -Xms256m -XX:MaxPermSize=250m -ea" />
</configuration>
<configuration default="true" type="AndroidJUnit" factoryName="Android JUnit">
<option name="TEST_OBJECT" value="class" />
<option name="WORKING_DIRECTORY" value="$MODULE_DIR$" />
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
</configuration>
<configuration default="true" type="Applet">
<option name="POLICY_FILE" value="$APPLICATION_HOME_DIR$/bin/appletviewer.policy" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration default="true" type="Application" factoryName="Application">
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration default="true" type="TestNG">
<option name="TEST_OBJECT" value="CLASS" />
<option name="WORKING_DIRECTORY" value="$MODULE_DIR$" />
<properties />
<listeners />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
<component name="ShelveChangesManager" show_recycled="false" />
<component name="SvnConfiguration">
<configuration />
</component>
@@ -419,41 +364,49 @@
<changelist id="a8c99766-6088-49be-bc69-6d9a3515f47d" name="Default" comment="" />
<created>1474396196987</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1474396196987</updated>
</task>
<servers />
</component>
<component name="ToolWindowManager">
<frame x="-8" y="-8" width="1382" height="744" extended-state="7" />
<editor active="false" />
<frame x="-8" y="-8" width="1936" height="1056" extended-state="6" />
<editor active="true" />
<layout>
<window_info id="Palette&#9;" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Designer" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Android Model" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="true" content_ui="tabs" />
<window_info id="Capture Analysis" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Android Monitor" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Captures" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="true" content_ui="tabs" />
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Capture Tool" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Gradle Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Build Variants" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="true" content_ui="tabs" />
<window_info id="Messages" active="true" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.30716723" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Gradle" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.24962178" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32935154" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="SLIDING" type="SLIDING" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
<window_info id="Image Layers" />
<window_info id="Resources Explorer" />
<window_info id="Project" order="0" visible="true" weight="0.17590618" />
<window_info id="Structure" order="1" weight="0.25" />
<window_info id="Captures" order="2" side_tool="true" weight="0.25" />
<window_info id="Build Variants" order="3" side_tool="true" />
<window_info id="Capture Tool" order="4" />
<window_info id="Palette&#9;" order="5" />
<window_info id="Favorites" order="6" side_tool="true" />
<window_info active="true" anchor="bottom" id="Build" sideWeight="0.49946696" visible="true" />
<window_info anchor="bottom" id="Android Profiler" show_stripe_button="false" />
<window_info anchor="bottom" id="Logcat" />
<window_info anchor="bottom" id="Message" order="0" />
<window_info anchor="bottom" id="Find" order="1" weight="0.3288889" />
<window_info anchor="bottom" id="Run" order="2" />
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
<window_info anchor="bottom" id="TODO" order="6" />
<window_info anchor="bottom" id="Version Control" order="7" />
<window_info anchor="bottom" id="Android Monitor" order="8" />
<window_info anchor="bottom" id="Terminal" order="9" />
<window_info anchor="bottom" id="Event Log" order="10" sideWeight="0.50053304" side_tool="true" visible="true" />
<window_info anchor="bottom" id="Gradle Console" order="11" side_tool="true" />
<window_info active="true" anchor="bottom" id="Messages" order="12" visible="true" weight="0.30716723" />
<window_info anchor="right" id="Device File Explorer" side_tool="true" />
<window_info anchor="right" id="Theme Preview" />
<window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
<window_info anchor="right" id="Capture Analysis" order="3" />
<window_info anchor="right" id="Gradle" order="4" />
<window_info anchor="right" id="Designer" order="5" />
<window_info anchor="right" id="Android Model" order="6" side_tool="true" />
</layout>
</component>
<component name="Vcs.Log.UiProperties">
@@ -464,201 +417,56 @@
<collection />
</option>
</component>
<component name="VcsContentAnnotationSettings">
<option name="myLimit" value="2678400000" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager />
<watches-manager />
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="16" column="5" selection-start-line="16" selection-start-column="5" selection-end-line="16" selection-end-column="5" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/local.properties">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/gradle.properties">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/settings.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="18" column="4" selection-start-line="18" selection-start-column="4" selection-end-line="18" selection-end-column="4" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="16" column="5" selection-start-line="16" selection-start-column="5" selection-end-line="16" selection-end-column="5" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/local.properties">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/gradle.properties">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/settings.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="18" column="4" selection-start-line="18" selection-start-column="4" selection-end-line="18" selection-end-column="4" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/settings.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="18" column="4" selection-start-line="18" selection-start-column="4" selection-end-line="18" selection-end-column="4" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/settings.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="16" column="5" selection-start-line="16" selection-start-column="5" selection-end-line="16" selection-end-column="5" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/settings.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/local.properties">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/gradle.properties">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<state relative-caret-position="119">
<caret line="7" column="5" selection-start-line="7" selection-start-column="5" selection-end-line="7" selection-end-column="5" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="38.444443">
<caret line="36" column="22" selection-start-line="36" selection-start-column="22" selection-end-line="36" selection-end-column="22" />
<folding>
<element signature="imports" expanded="false" />
<element signature="e#18771#18772#0" expanded="false" />
<element signature="e#18809#18810#0" expanded="false" />
<element signature="e#18861#18862#0" expanded="false" />
<element signature="e#18902#18903#0" expanded="false" />
</folding>
<state relative-caret-position="221">
<caret line="36" selection-start-line="36" selection-end-line="36" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/local.properties">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/gradle.properties">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/settings.gradle">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileChooserBridge.java">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.4228395">
<caret line="11" column="68" selection-start-line="11" selection-start-column="68" selection-end-line="11" selection-end-column="68" />
<folding />
<state relative-caret-position="357">
<caret line="25" selection-start-line="25" selection-end-line="25" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="204">
<caret line="12" column="11" selection-start-line="12" selection-start-column="11" selection-end-line="12" selection-end-column="11" />
</state>
</provider>
<provider editor-type-id="android-manifest" />
</entry>
<entry file="file://$PROJECT_DIR$/app/src/main/java/group/pals/android/lib/ui/filechooser/FileChooserActivity.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="208">
<caret line="23" column="24" selection-start-line="23" selection-start-column="24" selection-end-line="23" selection-end-column="24" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/app/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="153">
<caret line="9" column="5" selection-start-line="9" selection-start-column="5" selection-end-line="9" selection-end-column="5" />
</state>
</provider>
</entry>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="android-filechooser-AS" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<module external.linked.project.id="android-filechooser-AS" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
@@ -7,23 +7,13 @@
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="jdk" jdkName="1.7" jdkType="JavaSDK" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -1,92 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="android-filechooser-AS" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":app" />
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.3.2" />
<option name="LAST_KNOWN_AGP_VERSION" value="3.3.2" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" />
<option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugAndroidTestSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res;file://$MODULE_DIR$/build/generated/res/rs/debug;file://$MODULE_DIR$/build/generated/res/resValues/debug" />
<option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
<option name="LIBRARY_PROJECT" value="true" />
<option name="PROJECT_TYPE" value="1" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug" />
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes" />
<output-test url="file://$MODULE_DIR$/build/intermediates/javac/debugUnitTest/compileDebugUnitTestJavaWithJavac/classes" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debug/compileDebugAidl/out" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debug/compileDebugRenderscript/out" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debugAndroidTest/compileDebugAndroidTestAidl/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debugAndroidTest/compileDebugAndroidTestRenderscript/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/test/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
<orderEntry type="jdk" jdkName="Android API 28 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="support-v4-18.0.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:collections:28.0.0@jar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.1.1@jar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.core:common:1.1.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:28.0.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-v4:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-media-compat:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-fragment:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-utils:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:loader:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:viewpager:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:coordinatorlayout:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:drawerlayout:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:slidingpanelayout:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:customview:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:swiperefreshlayout:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:asynclayoutinflater:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-compat:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:versionedparcelable:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime:1.1.1@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:documentfile:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:localbroadcastmanager:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:print:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:interpolator:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:cursoradapter:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:viewmodel:1.1.1@aar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata:1.1.1@aar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata-core:1.1.1@aar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.core:runtime:1.1.1@aar" level="project" />
</component>
</module>

View File

@@ -1,12 +1,12 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 26
compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
minSdkVersion 15
targetSdkVersion 15
minSdkVersion 16
targetSdkVersion 28
}
buildTypes {
@@ -23,5 +23,5 @@ android {
}
dependencies {
compile 'com.android.support:support-v4:26.1.0'
compile 'com.android.support:support-v4:28.0.0'
}

View File

@@ -9,8 +9,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="group.pals.android.lib.ui.filechooser" >
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="23" />
</manifest>

View File

@@ -1,20 +1,30 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
maven {
url 'https://maven.google.com/'
name 'Google'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.3'
classpath 'com.android.tools.build:gradle:3.3.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
//classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.7.1'
}
}
allprojects {
repositories {
jcenter()
google()
}
}
dependencies {
task clean(type: Delete) {
delete rootProject.buildDir
}
android {
buildToolsVersion '23.0.2'
}

View File

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip

View File

@@ -10,7 +10,7 @@ using Android.Security.Keystore;
using Android.Preferences;
using Android.Util;
using Android.Widget;
using Androidx.Biometric;
using AndroidX.Biometric;
using AndroidX.Fragment.App;
using Java.IO;
using Java.Security.Cert;
@@ -21,104 +21,11 @@ using File = System.IO.File;
namespace keepass2android
{
public static class Kp2aLog
{
private static bool? _logToFile;
private static object _fileLocker = new object();
public static void Log(string message)
{
if (message != null)
Android.Util.Log.Debug("KP2A", message);
if (LogToFile)
{
lock (_fileLocker)
{
try
{
using (var streamWriter = System.IO.File.AppendText(LogFilename))
{
string stringToLog = DateTime.Now + ":" + DateTime.Now.Millisecond + " -- " + message;
streamWriter.WriteLine(stringToLog);
}
}
catch (Exception e)
{
Android.Util.Log.Debug("KP2A", "Couldn't write to log file. " + e);
}
}
}
}
private static string LogFilename
{
get { return Application.Context.FilesDir.CanonicalPath + "/keepass2android.log"; }
}
private static bool LogToFile
{
get
{
if (_logToFile == null)
_logToFile = System.IO.File.Exists(LogFilename);
return (bool)_logToFile;
}
}
public static event EventHandler<Exception> OnUnexpectedError;
public static void LogUnexpectedError(Exception exception)
{
Log(exception.ToString());
if (OnUnexpectedError != null)
OnUnexpectedError(null, exception);
}
public static void CreateLogFile()
{
if (!System.IO.File.Exists(LogFilename))
{
System.IO.File.Create(LogFilename).Dispose();
_logToFile = true;
}
}
public static void FinishLogFile()
{
if (System.IO.File.Exists(LogFilename))
{
_logToFile = false;
int count = 0;
while (System.IO.File.Exists(LogFilename + "." + count))
count++;
System.IO.File.Move(LogFilename, LogFilename + "." + count);
}
}
public static void SendLog(Context ctx)
{
if (!System.IO.File.Exists(LogFilename))
return;
Intent sendIntent = new Intent();
sendIntent.SetAction(Intent.ActionSend);
sendIntent.PutExtra(Intent.ExtraText, File.ReadAllText(LogFilename));
sendIntent.PutExtra(Intent.ExtraEmail, "crocoapps@gmail.com");
sendIntent.PutExtra(Intent.ExtraSubject, "Keepass2Android log");
sendIntent.SetType("text/plain");
ctx.StartActivity(Intent.CreateChooser(sendIntent, "Send log to..."));
}
}
public interface IBiometricAuthCallback
{
void OnBiometricAuthSucceeded();
void OnBiometricError(string toString);
void OnBiometricAttemptFailed(string message);
}
public class BiometricModule
@@ -214,6 +121,7 @@ namespace keepass2android
get
{
var result = BiometricManager.From(Activity).CanAuthenticate();
Kp2aLog.Log("BiometricHardware available = " + result);
return result == BiometricManager.BiometricSuccess
|| result == BiometricManager.BiometricErrorNoneEnrolled;
}
@@ -234,6 +142,7 @@ namespace keepass2android
private BiometricPrompt _biometricPrompt;
private FragmentActivity _activity;
private BiometricAuthCallbackAdapter _biometricAuthCallbackAdapter;
public BiometricCrypt(BiometricModule biometric, string keyId)
{
@@ -261,13 +170,14 @@ namespace keepass2android
public void StartListening(IBiometricAuthCallback callback)
{
StartListening(new BiometricAuthCallbackAdapter(callback, _activity));
_biometricAuthCallbackAdapter = new BiometricAuthCallbackAdapter(callback, _activity);
StartListening(_biometricAuthCallbackAdapter);
}
public void StopListening()
{
_biometricAuthCallbackAdapter?.IgnoreNextError();
_biometricPrompt?.CancelAuthentication();
}
public bool HasUserInterface
@@ -282,7 +192,7 @@ namespace keepass2android
Kp2aLog.Log("Fingerprint: StartListening ");
var executor = Executors.NewSingleThreadExecutor();
_biometricPrompt = new Androidx.Biometric.BiometricPrompt(_activity, executor, callback);
_biometricPrompt = new BiometricPrompt(_activity, executor, callback);
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
.SetTitle(_activity.GetString(AppNames.AppNameResource))
@@ -520,6 +430,7 @@ namespace keepass2android
{
private readonly IBiometricAuthCallback _callback;
private readonly Context _context;
private bool _ignoreNextError;
public BiometricAuthCallbackAdapter(IBiometricAuthCallback callback, Context context)
{
@@ -535,16 +446,24 @@ namespace keepass2android
public override void OnAuthenticationError(int errorCode, ICharSequence errString)
{
if (_ignoreNextError)
{
_ignoreNextError = false;
return;
}
new Handler(Looper.MainLooper).Post(() => _callback.OnBiometricError(errString.ToString()));
}
public override void OnAuthenticationFailed()
{
new Handler(Looper.MainLooper).Post(() => _callback.OnBiometricError(_context.Resources.GetString(Resource.String.fingerprint_not_recognized)));
new Handler(Looper.MainLooper).Post(() => _callback.OnBiometricAttemptFailed(_context.Resources.GetString(Resource.String.fingerprint_not_recognized)));
}
public void IgnoreNextError()
{
_ignoreNextError = true;
}
}
}

View File

@@ -27,7 +27,7 @@ namespace keepass2android
AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(ctx, Android.Resource.Style.ThemeHoloLightDialog));
builder.SetTitle(ctx.GetString(Resource.String.ChangeLog_title));
List<string> changeLog = new List<string>{
BuildChangelogString(ctx, Resource.Array.ChangeLog_1_08, "1.08-pre"),
BuildChangelogString(ctx, Resource.Array.ChangeLog_1_08, "1.08-r0"),
ctx.GetString(Resource.String.ChangeLog_1_07b),
ctx.GetString(Resource.String.ChangeLog_1_07),
ctx.GetString(Resource.String.ChangeLog_1_06),

View File

@@ -92,7 +92,7 @@ namespace keepass2android
{
public const String KeyEntry = "entry";
public const String KeyRefreshPos = "refresh_pos";
public const String KeyCloseAfterCreate = "close_after_create";
public const String KeyActivateKeyboard = "activate_keyboard";
public const String KeyGroupFullPath = "groupfullpath_key";
public const int requestCodeBinaryFilename = 42376;
@@ -480,13 +480,13 @@ namespace keepass2android
internal void StartNotificationsService(bool closeAfterCreate)
internal void StartNotificationsService(bool activateKeyboard)
{
Intent showNotIntent = new Intent(this, typeof (CopyToClipboardService));
showNotIntent.SetAction(Intents.ShowNotification);
showNotIntent.PutExtra(KeyEntry, new ElementAndDatabaseId(App.Kp2a.CurrentDb, Entry).FullId);
_appTask.PopulatePasswordAccessServiceIntent(showNotIntent);
showNotIntent.PutExtra(KeyCloseAfterCreate, closeAfterCreate);
showNotIntent.PutExtra(KeyActivateKeyboard, activateKeyboard);
StartService(showNotIntent);
}

View File

@@ -63,7 +63,9 @@ namespace keepass2android
const string IntentContinueWithEditing = "ContinueWithEditing";
EntryEditActivityState State
private PasswordFont _passwordFont = new PasswordFont();
EntryEditActivityState State
{
get { return App.Kp2a.EntryEditActivityState; }
}
@@ -401,6 +403,7 @@ namespace keepass2android
if (State.ShowPassword)
{
password.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
_passwordFont.ApplyTo(password);
confpassword.Visibility = ViewStates.Gone;
}
else
@@ -494,7 +497,7 @@ namespace keepass2android
ActionOnFinish closeOrShowError = new ActionOnFinish(this, (success, message, activity) => {
if (success)
{
activity.Finish();
activity?.Finish();
} else
{
OnFinish.DisplayMessage(activity, message, true);
@@ -502,6 +505,9 @@ namespace keepass2android
State.EditMode.InitializeEntry(State.Entry);
}
});
//make sure we can close the EntryEditActivity activity even if the app went to background till we get to the OnFinish Action
closeOrShowError.AllowInactiveActivity = true;
ActionOnFinish afterAddEntry = new ActionOnFinish(this, (success, message, activity) =>
{
@@ -569,7 +575,9 @@ namespace keepass2android
continue;
TextView valueView = (TextView)view.FindViewById(Resource.Id.value);
String value = valueView.Text;
String value = valueView.Text;
bool protect = ((CheckBox) view.FindViewById(Resource.Id.protection))?.Checked ?? State.EntryInDatabase.Strings.GetSafe(key).IsProtected;
entry.Strings.Set(key, new ProtectedString(protect, value));
@@ -1043,8 +1051,8 @@ namespace keepass2android
titleView.Text = title;
((TextView)ees.FindViewById(Resource.Id.value)).Text = pair.Value.ReadString();
((TextView)ees.FindViewById(Resource.Id.value)).TextChanged += (sender, e) => State.EntryModified = true;
((CheckBox)ees.FindViewById(Resource.Id.protection)).Checked = pair.Value.IsProtected;
_passwordFont.ApplyTo(((TextView)ees.FindViewById(Resource.Id.value)));
((CheckBox)ees.FindViewById(Resource.Id.protection)).Checked = pair.Value.IsProtected;
//ees.FindViewById(Resource.Id.edit_extra).Click += (sender, e) => DeleteAdvancedString((View)sender);
ees.FindViewById(Resource.Id.edit_extra).Click += (sender, e) => EditAdvancedString(ees.FindViewById(Resource.Id.edit_extra));
@@ -1105,6 +1113,7 @@ namespace keepass2android
View ees = (View) sender.Parent;
dlgView.FindViewById<TextView>(Resource.Id.title).Text = ees.FindViewById<TextView>(Resource.Id.extrakey).Text;
dlgView.FindViewById<EditText>(Resource.Id.value).Text = ees.FindViewById<EditText>(Resource.Id.value).Text;
_passwordFont.ApplyTo(dlgView.FindViewById<EditText>(Resource.Id.value));
Util.SetNoPersonalizedLearning(dlgView);
dlgView.FindViewById<CheckBox>(Resource.Id.protection).Checked = ees.FindViewById<CheckBox>(Resource.Id.protection).Checked;
@@ -1151,6 +1160,10 @@ namespace keepass2android
String password = State.Entry.Strings.ReadSafe(PwDefs.PasswordField);
PopulateText(Resource.Id.entry_password, password);
PopulateText(Resource.Id.entry_confpassword, password);
_passwordFont.ApplyTo(FindViewById<EditText>(Resource.Id.entry_password));
PopulateText(Resource.Id.entry_comment, State.Entry.Strings.ReadSafe (PwDefs.NotesField));

View File

@@ -16,7 +16,9 @@ using Android.Widget;
using Java.IO;
using keepass2android.Io;
#if !EXCLUDE_JAVAFILESTORAGE
using Keepass2android.Javafilestorage;
#endif
using KeePassLib.Serialization;
using KeePassLib.Utility;
@@ -457,7 +459,7 @@ namespace keepass2android
_activity.StartActivityForResult(i, _requestCode);
#else
Toast.MakeText(this, "File chooser is excluded!", ToastLength.Long).Show();
Toast.MakeText(Application.Context, "File chooser is excluded!", ToastLength.Long).Show();
#endif
return true;
}

View File

@@ -15,7 +15,6 @@ using Android.Widget;
using Java.Lang;
using KeePassLib.Keys;
using KeePassLib.Utility;
using Kotlin.Text;
using Enum = System.Enum;
using Exception = System.Exception;
@@ -120,26 +119,27 @@ namespace keepass2android
FindViewById(Resource.Id.radio_buttons).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.fingerprint_auth_container).Visibility = ViewStates.Gone;
FindViewById<CheckBox>(Resource.Id.show_keyboard_while_fingerprint).Checked =
Util.GetShowKeyboardDuringFingerprintUnlock(this);
FindViewById<CheckBox>(Resource.Id.show_keyboard_while_fingerprint).CheckedChange += (sender, args) =>
{
PreferenceManager.GetDefaultSharedPreferences(this)
.Edit()
.PutBoolean(GetString(Resource.String.ShowKeyboardWhileFingerprint_key), args.IsChecked)
.Commit();
};
UpdateKeyboardCheckboxVisibility();
}
FindViewById<CheckBox>(Resource.Id.close_database_after_failed).Checked =
Util.GetCloseDatabaseAfterFailedBiometricQuickUnlock(this);
private void UpdateKeyboardCheckboxVisibility()
FindViewById<CheckBox>(Resource.Id.close_database_after_failed).CheckedChange += (sender, args) =>
{
PreferenceManager.GetDefaultSharedPreferences(this)
.Edit()
.PutBoolean(GetString(Resource.String.CloseDatabaseAfterFailedBiometricQuickUnlock_key), args.IsChecked)
.Commit();
};
UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility();
}
private void UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility()
{
FindViewById(Resource.Id.show_keyboard_while_fingerprint).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.close_database_after_failed).Visibility = _unlockMode == FingerprintUnlockMode.QuickUnlock ? ViewStates.Visible : ViewStates.Gone;
}
private bool TrySetupSamsung()
@@ -249,7 +249,7 @@ namespace keepass2android
if (_samsungBiometry != null)
{
_unlockMode = newMode;
UpdateKeyboardCheckboxVisibility();
UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility();
ISharedPreferencesEditor edit = PreferenceManager.GetDefaultSharedPreferences(this).Edit();
edit.PutString(App.Kp2a.CurrentDb.CurrentFingerprintModePrefKey, _unlockMode.ToString());
@@ -260,17 +260,17 @@ namespace keepass2android
if (newMode == FingerprintUnlockMode.Disabled)
{
_unlockMode = newMode;
UpdateKeyboardCheckboxVisibility();
StoreUnlockMode();
UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility();
StoreUnlockMode();
return;
}
_desiredUnlockMode = newMode;
FindViewById(Resource.Id.radio_buttons).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.show_keyboard_while_fingerprint).Visibility = ViewStates.Gone;
UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility();
FindViewById(Resource.Id.fingerprint_auth_container).Visibility = ViewStates.Visible;
FindViewById(Resource.Id.fingerprint_auth_container).Visibility = ViewStates.Visible;
try
{
_enc = new BiometricEncryption(new BiometricModule(this), CurrentPreferenceKey);
@@ -312,7 +312,7 @@ namespace keepass2android
FindViewById(Resource.Id.fingerprint_auth_container).Visibility = ViewStates.Gone;
StoreUnlockMode();
UpdateKeyboardCheckboxVisibility();
UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility();
}, SUCCESS_DELAY_MILLIS);
@@ -332,7 +332,12 @@ namespace keepass2android
_fpTextView.PostDelayed(ResetErrorTextRunnable, ERROR_TIMEOUT_MILLIS);
}
void ResetErrorTextRunnable()
public void OnBiometricAttemptFailed(string message)
{
//ignore
}
void ResetErrorTextRunnable()
{
_fpTextView.SetTextColor(
_fpTextView.Resources.GetColor(Resource.Color.hint_color, null));
@@ -351,7 +356,7 @@ namespace keepass2android
//seems like not all Samsung Devices (e.g. Note 4) don't support the Android 6 fingerprint API
if (!TrySetupSamsung())
SetError(Resource.String.fingerprint_hardware_error);
UpdateKeyboardCheckboxVisibility();
UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility();
return;
}
if (!fpModule.IsAvailable)
@@ -360,8 +365,8 @@ namespace keepass2android
return;
}
ShowRadioButtons();
UpdateKeyboardCheckboxVisibility();
UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility();
}
protected override void OnPause()

View File

@@ -463,7 +463,7 @@ namespace keepass2android
new AlertDialog.Builder(this)
.SetTitle(Resource.String.autofill_enable)
.SetMessage(Resource.String.autofill_enable_failed)
.SetPositiveButton(Resource.String.ok, (o, eventArgs) => { })
.SetPositiveButton(Resource.String.Ok, (o, eventArgs) => { })
.Show();
const string autofillservicewasenabled = "AutofillServiceWasEnabled";
_prefs.Edit().PutBoolean(autofillservicewasenabled, true).Commit();
@@ -1239,7 +1239,7 @@ namespace keepass2android
{
Handler.Post(() =>
{
Toast.MakeText(ActiveActivity, "Unrecoverable error: " + Message, ToastLength.Long).Show();
Toast.MakeText(ActiveActivity ?? Application.Context, "Unrecoverable error: " + Message, ToastLength.Long).Show();
});
App.Kp2a.Lock(false);

View File

@@ -575,15 +575,13 @@ namespace keepass2android
}
}
int count = 1;
private string mDrawerTitle;
private MeasuringRelativeLayout.MeasureArgs _measureArgs;
private ActivityDesign _activityDesign;
private BiometricDecryption _biometricDec;
private bool _fingerprintPermissionGranted;
private PasswordActivityBroadcastReceiver _intentReceiver;
private PasswordActivityBroadcastReceiver _intentReceiver;
private int _appnameclickCount;
@@ -785,6 +783,8 @@ namespace keepass2android
}
Util.SetNoPersonalizedLearning(FindViewById<EditText>(Resource.Id.password_edit));
}
private void InitializeToolbarCollapsing()
@@ -926,7 +926,12 @@ namespace keepass2android
Toast.MakeText(this, message, ToastLength.Long).Show();
}
public void OnBiometricAuthSucceeded()
public void OnBiometricAttemptFailed(string message)
{
//ignore
}
public void OnBiometricAuthSucceeded()
{
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
@@ -1359,11 +1364,9 @@ namespace keepass2android
throw new NullPointerException("cpQuickUnlock");
App.Kp2a.SetQuickUnlockEnabled(cbQuickUnlock.Checked);
if (App.Kp2a.OfflineMode != _loadDbTaskOffline)
if ((_loadDbFileTask != null) && (App.Kp2a.OfflineMode != _loadDbTaskOffline))
{
if (_loadDbFileTask == null)
throw new NullPointerException("_loadDbFileTask");
if (App.Kp2a == null)
if (App.Kp2a == null)
throw new NullPointerException("App.Kp2a");
//keep the loading result if we loaded in online-mode (now offline) and the task is completed
if (!App.Kp2a.OfflineMode || !_loadDbFileTask.IsCompleted)
@@ -1759,24 +1762,19 @@ namespace keepass2android
}
else
{
bool showKeyboard = true;
bool showKeyboard = (Util.GetShowKeyboardDuringFingerprintUnlock(this));
if (!fingerprintInitialized)
showKeyboard = true;
EditText pwd = (EditText) FindViewById(Resource.Id.password_edit);
pwd.PostDelayed(() =>
{
InputMethodManager keyboard = (InputMethodManager) GetSystemService(InputMethodService);
if (showKeyboard)
keyboard.ShowSoftInput(pwd, 0);
else
if (showKeyboard)
{
pwd.RequestFocus();
keyboard.ShowSoftInput(pwd, 0);
}
else
keyboard.HideSoftInputFromWindow(pwd.WindowToken, HideSoftInputFlags.ImplicitOnly);
}, 50);
}

View File

@@ -80,34 +80,112 @@
</intent-filter>
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:mimeType="*/*" />
<data android:host="*" />
<data android:pathPattern=".*\\.kdbp" />
<data android:pathPattern=".*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\.kdbx" />
<data android:pathPattern=".*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
</intent-filter>
<!-- intent filter for opening database files
Note that this stopped working nicely with Android 7, see e.g. https://stackoverflow.com/a/26635162/292233
KP2A was using
<data android:scheme="content" />
<data android:mimeType="*/*" />
previously, but that leaded to complaints by users saying KP2A is showing up way too often, even when opening contacts and the like.
This is why this was reduced content with mimeType=application/octet-stream or content with pathPattern .
The scheme=file is still there for old OS devices. It's also queried by apps like Dropbox to find apps for a certain file type.
-->
<!-- This intent filter is for apps which use content with a URI containing the extension but no specific mimeType, e.g. ASTRO file manager -->
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="content" />
<data android:mimeType="*/*" />
<data android:host="*" />
<data android:pathPattern=".*\\.kdbp" />
<data android:pathPattern=".*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\.kdbx" />
<data android:pathPattern=".*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\.kdb" />
<data android:pathPattern=".*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
</intent-filter>
<!-- This intent filter is for apps which use content with a URI not containing the extension but at least specify mimeType=application/octet-stream, e.g. GoogleDrive or FolderSync -->
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="content" />
<data android:mimeType="application/octet-stream" />
<data android:host="*" />
</intent-filter>
<!-- This intent filter is for old OS versions (Android 6 and below) or for apps explicitly querying intents for a certain file:-URI -->
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:mimeType="*/*" />
<data android:host="*" />
<data android:pathPattern=".*\\.kdbp" />
<data android:pathPattern=".*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\.kdbx" />
<data android:pathPattern=".*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\.kdb" />
<data android:pathPattern=".*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
</intent-filter>
<intent-filter android:label="@string/kp2a_findUrl">
<action android:name="android.intent.action.SEND" />

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="145"
android:versionName="1.08-r0"
android:versionCode="147"
android:versionName="1.08-r1"
package="keepass2android.keepass2android"
android:installLocation="auto">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="29" />
@@ -85,7 +85,6 @@
<action android:name="kp2a.action.SelectCurrentDbActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.SEND" />
@@ -95,12 +94,27 @@
<data android:mimeType="application/*" />
</intent-filter>
<!-- intent filter for opening database files
Note that this stopped working nicely with Android 7, see e.g. https://stackoverflow.com/a/26635162/292233
KP2A was using
<data android:scheme="content" />
<data android:mimeType="*/*" />
previously, but that leaded to complaints by users saying KP2A is showing up way too often, even when opening contacts and the like.
This is why this was reduced content with mimeType=application/octet-stream or content with pathPattern .
The scheme=file is still there for old OS devices. It's also queried by apps like Dropbox to find apps for a certain file type.
-->
<!-- This intent filter is for apps which use content with a URI containing the extension but no specific mimeType, e.g. ASTRO file manager -->
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="*/*" />
<data android:host="*" />
@@ -135,7 +149,59 @@
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
</intent-filter>
<intent-filter android:label="@string/kp2a_findUrl">
<!-- This intent filter is for apps which use content with a URI not containing the extension but at least specify mimeType=application/octet-stream, e.g. GoogleDrive or FolderSync -->
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="content" />
<data android:mimeType="application/octet-stream" />
<data android:host="*" />
</intent-filter>
<!-- This intent filter is for old OS versions (Android 6 and below) or for apps explicitly querying intents for a certain file:-URI -->
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:mimeType="*/*" />
<data android:host="*" />
<data android:pathPattern=".*\\.kdbp" />
<data android:pathPattern=".*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\.kdbx" />
<data android:pathPattern=".*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\.kdb" />
<data android:pathPattern=".*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
</intent-filter>
<intent-filter android:label="@string/kp2a_findUrl">
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />

View File

@@ -69,11 +69,26 @@
<data android:mimeType="application/*" />
</intent-filter>
<!-- intent filter for opening database files
Note that this stopped working nicely with Android 7, see e.g. https://stackoverflow.com/a/26635162/292233
KP2A was using
<data android:scheme="content" />
<data android:mimeType="*/*" />
previously, but that leaded to complaints by users saying KP2A is showing up way too often, even when opening contacts and the like.
This is why this was reduced content with mimeType=application/octet-stream or content with pathPattern .
The scheme=file is still there for old OS devices. It's also queried by apps like Dropbox to find apps for a certain file type.
-->
<!-- This intent filter is for apps which use content with a URI containing the extension but no specific mimeType, e.g. ASTRO file manager -->
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="*/*" />
<data android:host="*" />
@@ -108,6 +123,58 @@
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
</intent-filter>
<!-- This intent filter is for apps which use content with a URI not containing the extension but at least specify mimeType=application/octet-stream, e.g. GoogleDrive or FolderSync -->
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="content" />
<data android:mimeType="application/octet-stream" />
<data android:host="*" />
</intent-filter>
<!-- This intent filter is for old OS versions (Android 6 and below) or for apps explicitly querying intents for a certain file:-URI -->
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:mimeType="*/*" />
<data android:host="*" />
<data android:pathPattern=".*\\.kdbp" />
<data android:pathPattern=".*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbp" />
<data android:pathPattern=".*\\.kdbx" />
<data android:pathPattern=".*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
<data android:pathPattern=".*\\.kdb" />
<data android:pathPattern=".*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>

View File

@@ -139,7 +139,7 @@ namespace keepass2android
//will return the results later
Intent i = new Intent(this, typeof (SelectCurrentDbActivity));
//don't show user notifications when an entry is opened.
var task = new SearchUrlTask() {UrlToSearchFor = _requestedUrl, ShowUserNotifications = false};
var task = new SearchUrlTask() {UrlToSearchFor = _requestedUrl, ShowUserNotifications = ShowUserNotificationsMode.WhenTotp};
task.ToIntent(i);
StartActivityForResult(i, RequestCodeQuery);
_startedQuery = true;

View File

@@ -48,7 +48,10 @@ namespace keepass2android
private int _quickUnlockLength;
private const int FingerprintPermissionRequestCode = 0;
public QuickUnlock()
private int numFailedAttempts = 0;
private int maxNumFailedAttempts = int.MaxValue;
public QuickUnlock()
{
_design = new ActivityDesign(this);
}
@@ -63,7 +66,9 @@ namespace keepass2android
_ioc = App.Kp2a.GetDbForQuickUnlock()?.Ioc;
if (_ioc == null)
if (_ioc == null)
{
Finish();
return;
@@ -147,11 +152,23 @@ namespace keepass2android
Util.SetNoPersonalizedLearning(FindViewById<EditText>(Resource.Id.QuickUnlock_password));
if (bundle != null)
numFailedAttempts = bundle.GetInt(NumFailedAttemptsKey, 0);
}
protected override void OnStart()
private const string NumFailedAttemptsKey = "FailedAttempts";
protected override void OnSaveInstanceState(Bundle outState)
{
base.OnSaveInstanceState(outState);
outState.PutInt(NumFailedAttemptsKey, numFailedAttempts);
}
protected override void OnStart()
{
base.OnStart();
DonateReminder.ShowDonateReminderIfAppropriate(this);
@@ -174,7 +191,18 @@ namespace keepass2android
Toast.MakeText(this, message, ToastLength.Long).Show();
}
public void OnBiometricAuthSucceeded()
public void OnBiometricAttemptFailed(string message)
{
numFailedAttempts++;
if (numFailedAttempts >= maxNumFailedAttempts)
{
FindViewById<ImageButton>(Resource.Id.fingerprintbtn).Visibility = ViewStates.Gone;
_biometryIdentifier.StopListening();
}
}
public void OnBiometricAuthSucceeded()
{
Kp2aLog.Log("OnFingerprintAuthSucceeded");
_biometryIdentifier.StopListening();
@@ -218,7 +246,14 @@ namespace keepass2android
return false;
}
BiometricModule fpModule = new BiometricModule(this);
if (um == FingerprintUnlockMode.QuickUnlock && Util.GetCloseDatabaseAfterFailedBiometricQuickUnlock(this))
{
maxNumFailedAttempts = 3;
}
BiometricModule fpModule = new BiometricModule(this);
Kp2aLog.Log("fpModule.IsHardwareAvailable=" + fpModule.IsHardwareAvailable);
if (fpModule.IsHardwareAvailable) //see FingerprintSetupActivity
_biometryIdentifier = new BiometricDecryption(fpModule, App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey, this,
@@ -232,9 +267,15 @@ namespace keepass2android
_biometryIdentifier = new BiometrySamsungIdentifier(this);
btn.Click += (sender, args) =>
{
if (_biometryIdentifier.Init())
_biometryIdentifier.StartListening(this);
};
if (_biometryIdentifier.Init())
{
if (numFailedAttempts < maxNumFailedAttempts)
{
_biometryIdentifier.StartListening(this);
}
}
};
Kp2aLog.Log("trying Samsung Fingerprint API...Seems to work!");
}
catch (Exception)
@@ -330,8 +371,9 @@ namespace keepass2android
CheckIfUnloaded();
InitFingerprintUnlock();
bool showKeyboard = ((!InitFingerprintUnlock()) || (Util.GetShowKeyboardDuringFingerprintUnlock(this)));
bool showKeyboard = true;
EditText pwd = (EditText)FindViewById(Resource.Id.QuickUnlock_password);
pwd.PostDelayed(() =>
@@ -347,7 +389,7 @@ namespace keepass2android
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
btn.Click += (sender, args) =>
{
if (_biometryIdentifier.HasUserInterface|| string.IsNullOrEmpty((string)btn.Tag) )
if ((_biometryIdentifier != null) && ((_biometryIdentifier.HasUserInterface)|| string.IsNullOrEmpty((string)btn.Tag) ))
{
_biometryIdentifier.StartListening(this);
}

View File

@@ -62,10 +62,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputLayout
android:layout_weight="1"
style="@style/EntryEditSingleLine_TextInputLayout">
<EditText
android:id="@+id/entry_password"
@@ -103,7 +104,7 @@
android:src="@drawable/ic_plus_button"
android:background="?android:selectableItemBackground" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
<EditText
android:id="@+id/entry_confpassword"
android:layout_width="match_parent"

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
@@ -68,11 +68,11 @@
android:background="?android:attr/selectableItemBackground" />
</LinearLayout>
<CheckBox
android:id="@+id/show_keyboard_while_fingerprint"
android:id="@+id/close_database_after_failed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:text="@string/ShowKeyboardDuringFingerprintAuth" />
android:text="@string/CloseDbAfterFailedAttempts" />
</LinearLayout>
<RelativeLayout
android:id="@+id/fingerprint_auth_container"

View File

@@ -138,12 +138,10 @@
android:layout_marginTop="16dp"
android:layout_marginLeft="4dp"
android:text="@string/hint_login_pass" />
<RelativeLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/password_edit"
android:layout_width="match_parent"
@@ -152,6 +150,7 @@
android:paddingTop="2dp"
android:singleLine="true"
android:inputType="textPassword"
android:layout_weight="1"
android:fontFamily="sans-serif"
android:hint="@string/hint_login_pass"
android:importantForAccessibility="no"/>
@@ -180,8 +179,8 @@
android:scaleType="fitXY"
android:background="?android:selectableItemBackground" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/keyfileLine"
android:layout_width="fill_parent"

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
>
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/switch_ime_text" />
<Button
android:id="@+id/btn_reopen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/switch_ime_reopen" />
<Button
android:id="@+id/btn_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cancel" />
</LinearLayout>

View File

@@ -1,905 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Generated by crowdin.com-->
<!--Generated by crowdin.net-->
<!--Kept because of a build issue without-->
<resources>
<string name="about_feedback">反馈</string>
<string name="about_homepage">主页</string>
<string name="AboutText">Keepass2Android 是一款支持 Keepass 2.x 数据库读写的密码管理应用。</string>
<string name="CreditsText">用户界面基于由 Brian Pellin 开发的 KeepassDroid。数据库操作的代码是基于 Dominik Reichl 开发的KeePass。根据google的创作共用3.0许可中的条款中的创建和申请条例的描述对android机器人进行了转载或者修改。</string>
<string name="CreditsTextSFTP">SFTP 由 JCraftInc. 创建的 JSch 库基于BSD许可证来支持</string>
<string name="CreditsIcons">锤子图标是由John Caserta通过Noun Project创建的。企鹅图标是由Adriano Emerick通过Noun Project创建的。羽毛图标是由 Jon Testa通过Noun Project创建的。苹果图标是由Ava Rowell通过Noun Project创建的。图片图标来自 https://icons8.com/icon/5570/Picture 。</string>
<string name="accept">接受</string>
<string name="deny">拒绝</string>
<string name="add_entry">添加条目</string>
<string name="edit_entry">编辑条目</string>
<string name="add_url_entry">创建URL条目</string>
<string name="add_group">添加群组</string>
<string name="add_group_title">添加群组</string>
<string name="edit_group_title">编辑群组</string>
<string name="algorithm">算法</string>
<string name="algorithm_colon">算法:</string>
<string name="app_name">Keepass2Android</string>
<string name="short_app_name">KP2A</string>
<string name="app_name_nonet">Keepass2Android 离线版</string>
<string name="short_app_name_nonet">KP2A 离线</string>
<string name="app_timeout">应用程序超时</string>
<string name="app_timeout_summary">应用程序处于非活动时锁定数据库。</string>
<string name="kill_app_label">结束应用程序进程</string>
<string name="show_kill_app">关闭按钮</string>
<string name="show_kill_app_summary">在密码界面显示一个结束应用程序进程的按钮</string>
<string name="application">应用程序</string>
<string name="application_settings">应用程序设置</string>
<string name="ShowGroupnameInSearchResult_title">在搜索结果中显示群组名</string>
<string name="ShowGroupnameInSearchResult_resume">在搜索结果中条目标题下显示群组名。如果几个条目具有相同的名称时会很有用。</string>
<string name="NavigationToGroupCompleted_message">当前显示群组:%1$s</string>
<string name="ShowGroupInEntry_title">在条目视图中显示群组名</string>
<string name="unknown_uri_scheme">对不起 Keepass2Android 不能处理返回的 URI %1$s。请联系开发者 </string>
<string name="Entry_singular">1个项目</string>
<string name="Entry_plural">%1$d 个项目</string>
<string name="IconSet_title">图标集</string>
<string name="IconSet_install">发现更多...</string>
<string name="security_prefs">安全</string>
<string name="display_prefs">显示</string>
<string name="password_access_prefs">密码输入接口</string>
<string name="QuickUnlock_prefs">快速解锁</string>
<string name="FileHandling_prefs">文件操作</string>
<string name="keyboard_prefs">键盘</string>
<string name="export_prefs">导出数据库...</string>
<string name="fingerprint_prefs">指纹解锁</string>
<string name="import_db_prefs">在内部的文件夹中导入数据库</string>
<string name="import_keyfile_prefs">将密钥文件导入到内部文件夹</string>
<string name="keyboardswitch_prefs">切换键盘</string>
<string name="OnlyAvailableForLocalFiles">仅适用于本地文件。</string>
<string name="FileIsInInternalDirectory">文件存储在内部目录中。</string>
<string name="DatabaseFileMoved">数据库文件已被复制到内部的文件夹。点击确定从新位置打开。注意: 不要忘记要定期将数据库导出到一个安全的地方!</string>
<string name="KeyfileMoved">密钥文件被复制到内部的文件夹。在你从当前位置删除之前请确保你已经有了一个安全的备份!</string>
<string name="KeyfileMoveRequiresRememberKeyfile">未记住密钥文件位置时不能使用内部文件夹。更改安全首选项。</string>
<string name="unlock_database_button">解锁</string>
<string name="unlock_database_title">解锁数据库</string>
<string name="brackets">括号</string>
<string name="cancel">取消</string>
<string name="ClearClipboard">剪贴板已清除。</string>
<string name="clipboard_timeout">剪贴板超时</string>
<string name="clipboard_timeout_summary">复制用户名或密码到剪贴板后清除的时间</string>
<string name="copy_username">复制用户名到剪贴板</string>
<string name="copy_password">复制密码到剪贴板</string>
<string name="available_through_keyboard">可通过 KP2A 键盘获得条目</string>
<string name="entry_is_available">可用</string>
<string name="not_possible_im_picker">无法打开输入法选择对话框,请手动激活键盘。</string>
<string name="please_activate_keyboard">请在系统设置中启用 Keepass2Android 键盘。</string>
<string name="creating_db_key">正在创建数据库密钥&#8230;</string>
<string name="current_group">当前群组</string>
<string name="current_group_root">当前群组:根群组</string>
<string name="database">数据库</string>
<string name="digits">数字</string>
<string name="disclaimer_formal">Keepass2Android 版权归 Philipp Crocoll软件不带有绝对担保是自由软件您可在遵循 GPL 2 或者更高版本的情况下重新发布。</string>
<string name="ellipsis">\u2026</string>
<string name="copy_to_clipboard">复制到剪贴板</string>
<string name="fingerprint_hint">触摸传感器</string>
<string name="fingerprint_description">确认指纹以继续</string>
<string name="fingerprint_fatal">无法设置指纹解锁:</string>
<string name="fingerprint_not_recognized">指纹无法识别。请重试</string>
<string name="fingerprint_success">指纹识别成功</string>
<string name="fingerprint_os_error">指纹识别需要Android 6.0或更新的版本。</string>
<string name="fingerprint_hardware_error">未检测到指纹识别硬件。</string>
<string name="fingerprint_no_enrolled">你还未在这个设备上录入过指纹。请先前往系统设置。</string>
<string name="disable_fingerprint_unlock">禁用指纹解锁</string>
<string name="enable_fingerprint_unlock">启用完整的指纹解锁</string>
<string name="enable_fingerprint_quickunlock">对快速解锁启用指纹解锁</string>
<string name="fingerprint_unlock_hint">触摸感应解锁数据库</string>
<string name="fingerprint_unlock_failed">指纹解锁失败。解密密钥已被 Android 操作系统标记为失效。这通常发生在注册了新的指纹或更改了安全设置后。 </string>
<string name="fingerprint_disabled_wrong_masterkey">解锁数据库失败:复合密钥无效。由于存储的主密钥不再有效,指纹解锁已被禁用。 </string>
<string name="fingerprint_reenable">请为这个新的主密码重新启用指纹解锁。</string>
<string name="fingerprint_reenable2">请用密码解锁,然后在数据库设置中重新启用指纹解锁。</string>
<string name="FingerprintInitFailed">初始化指纹传感器失败。 </string>
<string name="enable_fingerprint_unlock_Info">此选项将会把主密码保存在这台设备上使用Android密钥库加密并使用指纹授权进行保护。只有你的指纹才能解锁数据库。</string>
<string name="enable_fingerprint_quickunlock_Info">允许使用指纹认证来代替快速解锁代码。不再需要保存任何与你的主密码关联的信息。</string>
<string name="enter_filename">输入数据库名:</string>
<string name="entry_accessed">访问时间</string>
<string name="entry_cancel">取消</string>
<string name="entry_comment">特别提示</string>
<string name="entry_tags">标签</string>
<string name="entry_override_url">覆盖链接地址</string>
<string name="entry_confpassword">确认密码</string>
<string name="entry_created">创建时间:</string>
<string name="entry_expires">失效时间:</string>
<string name="entry_group_name">群组名</string>
<string name="entry_keyfile">密钥文件(可选)</string>
<string name="keyfile_heading">密钥文件</string>
<string name="entry_modified">修改时间</string>
<string name="entry_password">密码</string>
<string name="entry_save">保存</string>
<string name="entry_title">名称</string>
<string name="entry_url">网址:</string>
<string name="entry_user_name">用户名</string>
<string name="entry_extra_strings">额外的字符串字段</string>
<string name="entry_binaries">文件附件</string>
<string name="error_can_not_handle_uri">Keepass2Android 无法处理此链接地址。</string>
<string name="error_could_not_create_group">创建群组错误。</string>
<string name="error_could_not_create_parent">无法创建上级目录。</string>
<string name="error_database_exists">文件已存在。</string>
<string name="error_database_settinoverrgs">无法确定数据库设置。</string>
<string name="error_failed_to_launch_link">无法打开链接。</string>
<string name="error_filename_required">文件名不能为空。</string>
<string name="error_file_not_create">无法创建文件</string>
<string name="error_invalid_db">数据库无效。</string>
<string name="error_invalid_path">路径无效。</string>
<string name="error_no_name">用户名不能为空。</string>
<string name="error_nopass">密码或者密钥文件不能为空。</string>
<string name="error_pass_gen_type">必须选择至少一个密码生成类型</string>
<string name="error_pass_match">密码不匹配。</string>
<string name="error_rounds_not_number">密钥加密次数必须为数字。</string>
<string name="error_param_not_number">参数必须是一个数字</string>
<string name="error_title_required">标题不能为空。</string>
<string name="error_wrong_length">长度字段输入一个正整数</string>
<string name="FileNotFound">文件未找到。</string>
<string name="file_browser">文件浏览器</string>
<string name="generate_password">生成密码</string>
<string name="group">群组</string>
<string name="hint_comment">特别提示</string>
<string name="hint_conf_pass">确认密码</string>
<string name="hint_generated_password">生成密码</string>
<string name="hint_group_name">群组名</string>
<string name="hint_keyfile">密钥文件</string>
<string name="hint_length">长度</string>
<string name="hint_pass">密码</string>
<string name="hint_login_pass">密码</string>
<string name="hint_title">名称</string>
<string name="hint_url">链接地址</string>
<string name="hint_override_url">覆盖链接地址</string>
<string name="hint_tags">标签1,标签2 </string>
<string name="hint_username">用户名</string>
<string name="InvalidPassword">密码或密钥文件无效。</string>
<string name="invalid_algorithm">无效的算法</string>
<string name="invalid_db_sig">数据库格式无法识别。</string>
<string name="keyfile_does_not_exist">密钥文件不存在。</string>
<string name="no_keyfile_selected">没有选定的密钥文件。</string>
<string name="keyfile_is_empty">密钥文件是空的。</string>
<string name="length">长度</string>
<string name="list_size_title">群组列表大小</string>
<string name="list_size_summary">群组列表字体大小</string>
<string name="loading_database">加载数据库中&#8230;</string>
<string name="lowercase">小写</string>
<string name="MaskedPassword">*****</string>
<string name="maskpass_title">密码掩码</string>
<string name="maskpass_summary">默认隐藏密码</string>
<string name="menu_about">关于</string>
<string name="menu_change_key">更改主密钥</string>
<string name="menu_copy_pass">复制密码</string>
<string name="menu_copy_user">复制用户</string>
<string name="menu_create">创建</string>
<string name="menu_app_settings">设置</string>
<string name="menu_db_settings">数据库设置</string>
<string name="menu_delete">删除</string>
<string name="menu_copy">创建副本</string>
<string name="menu_move">移动到其他群组</string>
<string name="menu_move_light">移动</string>
<string name="menu_navigate">导航字父群组</string>
<string name="menu_donate">捐出一瓶啤酒钱......</string>
<string name="menu_edit">编辑</string>
<string name="menu_hide_password">隐藏密码</string>
<string name="menu_lock">锁定数据库</string>
<string name="menu_open">打开</string>
<string name="menu_close">关闭</string>
<string name="menu_rename">重命名</string>
<string name="menu_search">搜索</string>
<string name="menu_search_advanced">高级搜索</string>
<string name="menu_url">转到链接地址</string>
<string name="menu_change_db">更改数据库...</string>
<string name="menu_show_all">显示所有字段</string>
<string name="minus"></string>
<string name="never">从不</string>
<string name="yes"></string>
<string name="no"></string>
<string name="no_keys">数据库或群组中无条目</string>
<string name="no_results">无匹配结果</string>
<string name="no_url_handler">没有处理这个链接地址的程序。</string>
<string name="open_recent">打开最近数据库(点击打开)</string>
<string name="omitbackup_title">不搜索备份和回收站中的条目</string>
<string name="omitbackup_summary">从搜索结果中忽略备份和回收站群组</string>
<string name="pass_filename">KeePass 数据库文件名</string>
<string name="password_title">输入数据库密码</string>
<string name="master_key_type">选择主密钥类型:</string>
<string name="progress_create">创建新数据库中&#8230;</string>
<string name="create_database">创建数据库</string>
<string name="progress_title">工作中&#8230;</string>
<string name="remember_keyfile_summary">记住密钥文件的位置</string>
<string name="remember_keyfile_title">保存密钥文件</string>
<string name="remove_from_filelist">移除</string>
<string name="edit">编辑</string>
<string name="rijndael">Rijndael 加密AES</string>
<string name="root">管理员权限</string>
<string name="KeyDerivFunc">密匙派生函数</string>
<string name="rounds">加密次数</string>
<string name="rounds_explaination">更高的加密次数能对暴力攻击提供额外保护,但也会增加加载和保存的时间。</string>
<string name="rounds_hint">次数</string>
<string name="argon2memory">内存(字节)</string>
<string name="argon2parallelism">并行处理</string>
<string name="database_name">数据库名称</string>
<string name="default_username">新条目的默认用户名</string>
<string name="saving_database">正在保存数据库&#8230;</string>
<string name="exporting_database">正在导出数据库...</string>
<string name="export_database_successful">数据库导出成功 </string>
<string name="space">空格</string>
<string name="search_label">搜索</string>
<string name="show_password">显示密码</string>
<string name="sort_menu">排序...</string>
<string name="sort_name">按名称排序</string>
<string name="sort_db">按创建日期排序</string>
<string name="sort_moddate">按修改日期排序</string>
<string name="sort_default">保持默认顺序</string>
<string name="special">特别</string>
<string name="search_hint">查找内容</string>
<string name="search_results">搜索结果</string>
<string name="search_in">在...中搜索</string>
<string name="select_other_entry">选择另一条目</string>
<string name="select_group_then_add">打开所需的组,然后按\"%1$s\"</string>
<string name="insert_element_here">在此处插入</string>
<string name="twofish">双鱼算法</string>
<string name="underline">下划线</string>
<string name="unsupported_db_version">不支持的数据库版本。</string>
<string name="uppercase">大写</string>
<string name="warning_read_only">你的 SD 卡目前是只读状态。您可能无法将更改保存到数据库。</string>
<string name="warning_unmounted">你的 SD 卡目前尚未挂载到您的设备上。你将无法加载或创建您的数据库。</string>
<string name="version_label">版本</string>
<string name="version_history">版本历史记录</string>
<string name="author">Keepass2Android 由 Philipp Crocoll 开发。</string>
<string name="further_authors">感谢 %1$s 贡献的代码。</string>
<string name="designers">感谢 %1$s 提供的图标和界面设计.</string>
<string name="credit_plugin1">包含在 KP2A 中的双鱼算法插件是由 Scott Greenberg 为 Keepass 开发的。</string>
<string name="credit_android_filechooser">Android 文件选择器是由 Hai Bison 开发的</string>
<string name="credit_keyboard">KP2A 键盘基于 Android 开放源代码项目的姜饼键盘,并使用 Klaus Weidner 的黑客键盘插件管理器代码。</string>
<string name="please_note">请注意</string>
<string name="contributors">贡献者</string>
<string name="regular_expression">正则表达式</string>
<string name="TanExpiresOnUse_title">TAN 使用到期</string>
<string name="TanExpiresOnUse_summary">当使用它们时标记 TAN 条目过期</string>
<string name="ShowUsernameInList_title">在列表中显示用户名</string>
<string name="ShowUsernameInList_summary">在条目标题下方显示用户名,对多账户或 TANs 很有用。</string>
<string name="RememberRecentFiles_title">记忆数据库</string>
<string name="RememberRecentFiles_summary">记忆最近打开过的数据库并在开启数据库屏显示。</string>
<string name="kp2a_findUrl">Keepass2Android查找密码</string>
<string name="excludeExpiredEntries">排除过期的条目</string>
<string name="search_options">选项</string>
<string name="caseSensitive">区分大小写</string>
<string name="start_open_file">打开文件...</string>
<string name="start_create">创建新的数据库...</string>
<string name="start_open_url">打开链接地址L...</string>
<string name="start_create_import">导入文件到新的数据库...</string>
<string name="enter_filename_details_url">必须指定包含类似 http:// 的完整链接地址</string>
<string name="enter_filename_details_create_import">所导入的文件将在下一步被选中</string>
<string name="enable_quickunlock">启用快速解锁</string>
<string name="QuickUnlock_label">输入你密码的最后 %1$d 个字符</string>
<string name="QuickUnlock_label_secure">输入快速解锁密码:</string>
<string name="QuickUnlock_button">快速解锁!</string>
<string name="QuickUnlock_lockButton">关闭数据库</string>
<string name="QuickUnlockDefaultEnabled_title">默认启用快速解锁</string>
<string name="QuickUnlockDefaultEnabled_summary">设定是否在默认情况下启用快速解锁</string>
<string name="ViewDatabaseSecure_title">数据库保护显示</string>
<string name="ViewDatabaseSecure_summary">如果启用,截图和应用程序缩略图将不会展示在最近的应用程序列表中。</string>
<string name="QuickUnlockIconHidden_title">隐藏快速锁定图标</string>
<string name="QuickUnlockIconHidden_summary">不幸无法显示快速解锁的通知图标。选择此选项可使用一个透明的图标。</string>
<string name="QuickUnlockIconHidden16_title">隐藏快速锁定图标</string>
<string name="QuickUnlockIconHidden16_summary">快速解锁需要一条通知以能正常运行。选中本选项以显示一条不带图标的通知。</string>
<string name="QuickUnlockLength_title">快速解锁密钥的长度</string>
<string name="QuickUnlockLength_summary">快速解锁密码的最大长度</string>
<string name="QuickUnlockHideLength_title">隐藏快速解锁密码长度</string>
<string name="QuickUnlockHideLength_summary">若启用,快速解锁所需的密码长度不会再显示在快速解锁界面上。</string>
<string name="QuickUnlock_fail">解锁失败:密码错误!</string>
<string name="BinaryDirectory_title">文件附件目录</string>
<string name="BinaryDirectory_summary">附件所保存到的目录位置</string>
<string name="SaveAttachmentDialog_title">保存附件</string>
<string name="SaveAttachmentDialog_text">请选择保存该附件的位置。</string>
<string name="SaveAttachmentDialog_save">保存到 SD 卡</string>
<string name="SaveAttachmentDialog_open">保存到缓存并打开</string>
<string name="ShowAttachedImage">在内部图像查看器中显示</string>
<string name="SaveAttachment_doneMessage">保存文件到 %1$s 。</string>
<string name="SaveAttachment_Failed">无法保存附件到 %1$s 。</string>
<string name="AddUrlToEntryDialog_title">记忆搜索文本?</string>
<string name="AddUrlToEntryDialog_text">你想存储在选定项目中的搜索文本「%1$s」来在下次搜索时自动匹配吗</string>
<string name="error_invalid_expiry_date">有效期限的日期或时间格式有误!</string>
<string name="error_string_key">每个字符串的字段名称不能为空。</string>
<string name="error_string_duplicate_key">字段名称不能使用两次 (%1$s)。</string>
<string name="field_name">字段名</string>
<string name="field_value">字段值</string>
<string name="protection">受保护的字段</string>
<string name="add_binary">添加附件...</string>
<string name="add_extra_string">添加额外的字符串</string>
<string name="delete_extra_string">删除额外的字符串</string>
<string name="database_loaded_quickunlock_enabled">%1$s已锁定快速解锁已启用。</string>
<string name="database_loaded_unlocked">%1$s已解锁。</string>
<string name="credentials_dialog_title">输入服务器的证书</string>
<string name="UseFileTransactions_title">文件记录</string>
<string name="UseFileTransactions_summary">使用文件记录来写数据库</string>
<string name="LockWhenScreenOff_title">在锁屏时锁定</string>
<string name="LockWhenScreenOff_summary">当锁屏时锁定数据库。</string>
<string name="ClearPasswordOnLeave_title">清除已输入的主密码</string>
<string name="ClearPasswordOnLeave_summary">当没有解锁数据库就退出时,清除已输入的主密码。</string>
<string name="LockWhenNavigateBack_title">离开应用时锁定</string>
<string name="LockWhenNavigateBack_summary">当通过点按返回键离开本应用时锁定数据库</string>
<string name="ActivateSearchViewOnStart_title">启动时自动激活搜索区域</string>
<string name="ActivateSearchViewOnStart_summary">当进入分组视图或开始搜索条目时自动将焦点转至搜索区域</string>
<string name="NoDonateOption_title">隐藏捐赠选项</string>
<string name="NoDonateOption_summary">本设置为捐赠者设定。只有当使用 Keepass2Android 一段时间后才可用。</string>
<string name="NoDonateOption_question">若没有捐款,本应用就不存在也不会有不断地改进!若您尚未捐赠,请考虑现在捐赠吧!</string>
<string name="NoDonationReminder_title">不再要求捐赠</string>
<string name="NoDonationReminder_summary">我不打算捐赠或已经捐赠过。即使是在作者生日当天,也不要再向我请求捐赠。</string>
<string name="UseOfflineCache_title">数据库缓存</string>
<string name="CreateBackups_title">本地备份</string>
<string name="CreateBackups_summary">在成功进入数据库后创建本地备份。</string>
<string name="UpdatingBackup">正在更新本地备份...</string>
<string name="LocalBackupOf">本地备份:%1$s</string>
<string name="AcceptAllServerCertificates_title">SSL 证书</string>
<string name="AcceptAllServerCertificates_summary">定义当证书验证失败时的行为。注意:如果验证失败您可以在您的设备上安装证书!</string>
<string name="ClearOfflineCache_title">清除缓存?</string>
<string name="CheckForFileChangesOnSave_title">检查修改</string>
<string name="CheckForFileChangesOnSave_summary">检查文件是否在保存变更之前被外部修改。</string>
<string name="CheckForDuplicateUuids_title">检查重复的 UUID</string>
<string name="CheckForDuplicateUuids_summary">通过检查数据库文件是否有多个相同 ID 的项目,来判断数据库是否损坏。这可能会导致意外的行为。</string>
<string name="ShowCopyToClipboardNotification_title">剪贴板通知</string>
<string name="ShowCopyToClipboardNotification_summary">让用户名和密码可通过通知栏和剪贴板访问。谨防密码嗅探器 </string>
<string name="ShowSeparateNotifications_title">独立的通知</string>
<string name="ShowSeparateNotifications_summary">为复制账户信息和激活键盘分别显示通知</string>
<string name="AccServiceAutoFill_prefs">自动填充服务(辅助功能)</string>
<string name="AutoFill_prefs">自动填充服务</string>
<string name="ShowKp2aKeyboardNotification_title">KP2A 键盘通知</string>
<string name="ShowKp2aKeyboardNotification_summary">使整个条目可通过 KP2A 键盘获取 (推荐)。</string>
<string name="OpenKp2aKeyboardAutomatically_title">切换键盘</string>
<string name="OpenKp2aKeyboardAutomatically_summary">当从浏览器搜索或键盘后可用通过 KP2A 键盘输入时,打开键盘选择对话框。</string>
<string name="kp2a_switch_rooted">自动切换键盘</string>
<string name="kp2a_switch_rooted_summary">条目打开时,自动切换到 KP2A 键盘。需要正确设定的 KeyboardSwap 插件或在获取root权限的设备的安全设置应用程序中获得许可。 </string>
<string name="get_keyboardswap">安装 KeyboardSwap 插件</string>
<string name="get_keyboardswap_summary">此插件可以在没有root权限的情况下切换 KP2A 键盘。要求ADB。 </string>
<string name="OpenKp2aKeyboardAutomaticallyOnlyAfterSearch_title">仅在搜索后自动切换</string>
<string name="OpenKp2aKeyboardAutomaticallyOnlyAfterSearch_summary">仅当通过分享链接的方式打开条目时自动切换键盘(但不包括其它打开条目的方式)</string>
<string name="AutoSwitchBackKeyboard_title">切换为原来的键盘</string>
<string name="AutoSwitchBackKeyboard_summary">没有打开条目时,切换回原来的键盘。</string>
<string name="ShowUnlockedNotification_title">解锁时通知图标</string>
<string name="ShowUnlockedNotification_summary">当数据库处于解锁状态栏持续显示通知。</string>
<string name="IconVisibilityInfo_Android8_text">Android 8.0的通知引入了新的行为。若你想隐藏Keepass2Android的通知图标请前往系统设置将通知的重要性设为中等。</string>
<string name="IconVisibilityInfo_Android8_btnSettings">打开设置</string>
<string name="DontCare">无所谓</string>
<string name="DocumentAccessRevoked">Keepass2Android无法访问此文件。文件可能已被删除或其访问权限受限。请使用“更改数据库”重新打开文件。</string>
<string name="PreloadDatabaseEnabled_title">预载入数据库文件</string>
<string name="PreloadDatabaseEnabled_summary">当输入密码项时启动后台加载或下载数据库文件。</string>
<string name="AskOverwriteBinary">是否要以相同的名字覆盖现有的文件?</string>
<string name="AskOverwriteBinary_title">覆盖已存在的文件?</string>
<string name="AskOverwriteBinary_yes">覆盖</string>
<string name="AskOverwriteBinary_no">重命名</string>
<string name="AttachFailed">未能添加附件。</string>
<string name="RecycleBin">回收站</string>
<string name="AskDeletePermanentlyEntry">是否要永久删除此条目?按否取消。</string>
<string name="AskDeletePermanentlyGroup">是否要永久删除此群组?按否将其放入回收站。</string>
<string name="AskDeletePermanentlyItems">你想要永久删除选定的元素?选否回到垃圾箱。</string>
<string name="AskDeletePermanentlyEntryNoRecycle">你想完全的删除这个登陆记录吗?</string>
<string name="AskDeletePermanentlyGroupNoRecycle">你想永久的删除这个组吗?</string>
<string name="AskDeletePermanentlyItemsNoRecycle">你想永久的删除已选择的元素吗?</string>
<string name="AskDeletePermanently_title">确定永久删除?</string>
<string name="AskReloadFile_title">重新载入文件?</string>
<string name="AskReloadFile">当前所打开的文件已被别的程序所更改,是否要重新载入?</string>
<string name="AskDiscardChanges">确认放弃之前所做的更改?(保存按钮在顶部)</string>
<string name="AskDiscardChanges_title">放弃更改?</string>
<string name="suggest_improvements">建议或投票改进</string>
<string name="rate_app">为本应用评分</string>
<string name="translate_app">翻译 KP2A</string>
<string name="AddingEntry">添加条目...</string>
<string name="AddingGroup">添加群组...</string>
<string name="DeletingEntry">删除条目...</string>
<string name="DeletingGroup">删除群组...</string>
<string name="DeletingItems">删除元素中&#8230;</string>
<string name="SettingPassword">设置密码...</string>
<string name="UndoingChanges">撤消更改...</string>
<string name="TransformingKey">变更主密钥...</string>
<string name="DecodingDatabase">解码数据库...</string>
<string name="ParsingDatabase">解析数据库...</string>
<string name="CheckingTargetFileForChanges">检查目标文件的更改...</string>
<string name="TitleSyncQuestion">合并更改吗?</string>
<string name="MessageSyncQuestion">数据库文件被外目修改。你想在保存之前载入并合并已有的更改吗?如果你想覆盖外部更改选择「不」。</string>
<string name="SynchronizingDatabase">合并更改...</string>
<string name="YesSynchronize">是的,合并</string>
<string name="NoOverwrite">不,覆盖</string>
<string name="SynchronizingCachedDatabase">同步缓存的数据库...</string>
<string name="FilesInSync">文件同步中。</string>
<string name="SynchronizedDatabaseSuccessfully">数据库同步成功 </string>
<string name="CheckingDatabaseForChanges">检查数据库更改...</string>
<string name="RemoteDatabaseUnchanged">未检测到变化。</string>
<string name="SynchronizingOtpAuxFile">正在同步一次性密码辅助文件&#8230;</string>
<string name="database_file">数据库文件</string>
<string name="otp_aux_file">一次性密码辅助文件</string>
<string name="ErrorOcurred">发生错误:</string>
<string name="DuplicateUuidsError">数据库损坏发现重复的ID。你曾使用Minikeepass编辑请用Keepass 2 for PC并选择创建新的ID重新导入到新的数据库。</string>
<string name="DuplicateUuidsErrorAdditional">您可以在 设置/应用设置/文件处理/检查重复的 UUID 中关闭此错误消息。请注意您可能碰到意外的情况,建议您立即修复数据库。</string>
<string name="synchronize_database_menu">同步数据库...</string>
<string name="CannotMoveGroupHere">不能将群组移动到这。</string>
<string name="donate_question">今天是慕尼黑啤酒节 !如果你喜欢 Keepass2Android今天难道不是给我买一杯啤酒的好日子吗</string>
<string name="donate_bday_question">5月10日今天是我的生日如果您喜欢本应用为什么不送我点生日问候与生日礼物这会让我非常高兴:-)</string>
<string name="donate_missedbday_question">您错过了我5月10日的生日如果您喜欢本应用为什么不送我点生日问候与生日礼物还不算太晚这会让我非常高兴:-)</string>
<string name="ok_donate">告诉我更多 </string>
<string name="no_thanks">不,我不是那么喜欢。</string>
<string name="enter_http_login_title">输入 WebDav 登录数据:</string>
<string name="hint_http_url">文件夹或文件 URL (如: mycloud.me.com/webdav/)</string>
<string name="enter_owncloud_login_title">输入 OwnCloud 登录信息:</string>
<string name="hint_owncloud_url">OwnCloud 地址 (例如: owncloud.me.com)</string>
<string name="hint_sftp_host">主机(比如: 192.168.0.1</string>
<string name="hint_sftp_port">端口</string>
<string name="initial_directory">初始目录 (可选):</string>
<string name="enter_sftp_login_title">输入 SFTP 登录数据:</string>
<string name="enter_ftp_login_title">输入 FTP 登录数据:</string>
<string name="select_storage_type">选择存储类型:</string>
<string name="filestoragename_file">本地文件</string>
<string name="filestoragename_androidget">从第三方应用程序中获取</string>
<string name="filestoragename_androidsend">发送到第三方应用程序</string>
<string name="filestoragename_ftp">FTP</string>
<string name="filestoragename_http">HTTP (WebDav)</string>
<string name="filestoragename_https">HTTPS (WebDav)</string>
<string name="filestoragename_owncloud">OwnCloud</string>
<string name="filestoragename_dropbox">Dropbox</string>
<string name="filestoragename_dropboxKP2A">DropboxKP2A 文件夹)</string>
<string name="filestoragehelp_dropboxKP2A">如果你不想让 KP2A 访问整个 Dropbox您可以选中此选项。它将只有访问 应用/Keepass2Android 文件夹的权限。特别适合创建一个新的数据库。如果您已经有一个数据库,点击此选项将创建该新文件夹,然后将你在电脑上的数据库文件放在此文件夹内,然后再选该选项,并以打开该文件。</string>
<string name="filestoragename_gdrive">Google Drive</string>
<string name="filestoragename_onedrive">OneDrive</string>
<string name="filestoragename_sftp">SFTPSSH 文件传输)</string>
<string name="filestoragename_content">系统文件选择器</string>
<string name="filestorage_setup_title">初始化文件访问</string>
<string name="database_location">数据库位置</string>
<string name="help_database_location">您可以在您的 Android 设备或云端存储你的数据库(非离线版本)。 即使您处于脱机状态 Keepass2Android 也依然可以使用。数据库采用安全的 AES 256 位加密,若没有您的密码任何人都无法访问它。我们建议选择存储在 Dropbox在所有设备上皆可访问甚至还提供了文件的早期版本备份。</string>
<string name="hint_database_location">选择数据库存储的位置:</string>
<string name="button_change_location">更改位置</string>
<string name="help_quickunlock">一旦启用即便数据库被锁定Keepass2Android将仍然后台运行。这样允许仅用主密码的一小部分来解锁数据库。</string>
<string name="master_password">主密码</string>
<string name="help_master_password">您的数据库是使用您在此处输入的密码进行加密的。为了保证数据库的安全请选择强密码 !建议:同时使用大小写英文字母、数字及特殊字符。</string>
<string name="hint_master_password">请选择一个主密码来保护您的数据库:</string>
<string name="key_file">密钥文件</string>
<string name="help_key_file">密钥文件简单来说就是保存成文件的密码。密钥文件通常比密码复杂和可靠得多,但是也更难将其隐藏。如果您将数据库保存在云端,千万不要把密钥文件也放上去!这样做会使密钥文件变得毫无意义!重要提示:创建数据库后,不要对密钥文件做出修改。</string>
<string name="hint_key_file">勾选以在使用主密码之余额外使用一个密钥文件:</string>
<string name="use_key_file">使用密钥文件</string>
<string name="error_adding_keyfile">添加密钥文件时出错 </string>
<string name="init_otp">加载一次性密码辅助文件......</string>
<string name="otp_explanation">通过 NFC 刷您的 Yubikey NEO 设备来输入下一个一次性密码。</string>
<string name="otp_hint">一次性密码 %1$d</string>
<string name="CouldntLoadOtpAuxFile">不能加载一次性密码文件 </string>
<string name="CouldntLoadOtpAuxFile_Hint">请使用 KeePass 2.x电脑端的 OtpKeyProv 插件来配置您的数据库使用 OTPs </string>
<string name="otp_discarded_because_no_db">请先选择数据库。出于安全原因,一次性密码将被丢弃。</string>
<string name="otp_discarded_no_space">一次性密码已丢弃:所有一次性密码已进入。</string>
<string name="otp_discarded_because_db_open">请先关闭数据库。一次性密码已丢弃。</string>
<string name="otps_pending">(一个或多个一次性密码已经可用)</string>
<string name="otpsecret_hint">一次性密码例如01 23 ab cd</string>
<string name="CouldntParseOtpSecret">解析一次性密码错误!</string>
<string name="OtpKeyError">无法创建一次性密码密钥!确保你输入了正确的 OTPs。</string>
<string name="ErrorUpdatingOtpAuxFile">更新一次性密码辅助文件时出错 </string>
<string name="SavingOtpAuxFile">正在保存一次性密码辅助文件...</string>
<string name="bad_resp">挑战响应不正确</string>
<string name="CouldntLoadChalAuxFile">无法加载辅助挑战文件!</string>
<string name="CouldntLoadChalAuxFile_Hint">请在 KeePass 2.x (PC) 中使用 KeeChallenge 插件,以使用挑战—响应配置您的数据库!</string>
<string name="ErrorUpdatingChalAuxFile">更新一次性密码辅助文件时出错 </string>
<string name="TrayTotp_SeedField_title">一次性密码种子字段名称</string>
<string name="TrayTotp_SeedField_summary">如果您在使用 Keepass 2 插件 \"TrayTotp\" 为非默认设置,在电脑上输入设置种子字段的字段名称。</string>
<string name="TrayTotp_SettingsField_title">TOTP 字段名称设置</string>
<string name="TrayTotp_SettingsField_summary">在这里输入设置字段的字段名称 TrayTotp</string>
<string name="TrayTotp_prefs">TrayTotp</string>
<string name="DebugLog_prefs_prefs">调试用日志文件</string>
<string name="DebugLog_title">使用日志文件</string>
<string name="DebugLog_summary">将应用输出写入本地日志文件</string>
<string name="DebugLog_send">发送调试日志...</string>
<string name="loading">载入中...</string>
<string name="plugins">插件</string>
<string name="plugin_packagename">包名称:</string>
<string name="plugin_description">说明(未验证):</string>
<string name="plugin_author">作者(未验证):</string>
<string name="plugin_enabled">已启用</string>
<string name="plugin_disabled">已禁用</string>
<string name="plugin_web">发现在线插件</string>
<string name="plugin_scopes">作用域</string>
<string name="not_enabled">未启用</string>
<string name="query_credentials_for_url">%1$s 正在请求 %2$s 的证书</string>
<string name="query_credentials">%1$s 正在请求证书。请选择一个条目。</string>
<string name="plugin_enabled_checkbox">已启用</string>
<string name="SCOPE_DATABASE_ACTIONS_title">数据库操作通知</string>
<string name="SCOPE_DATABASE_ACTIONS_explanation">当数据库进行打开、关闭或保存操作时,插件会发出通知。</string>
<string name="SCOPE_CURRENT_ENTRY_title">当前条目数据</string>
<string name="SCOPE_CURRENT_ENTRY_explanation">插件会获取到当前数据库的所有数据,并允许它提供操作并修改显示。</string>
<string name="SCOPE_QUERY_CREDENTIALS_FOR_OWN_PACKAGE_title">查询自己的凭据</string>
<string name="SCOPE_QUERY_CREDENTIALS_FOR_OWN_PACKAGE_explanation">插件将获准查询与它相关联当应用程序包的证书。</string>
<string name="SCOPE_QUERY_CREDENTIALS_title">查询凭据</string>
<string name="SCOPE_QUERY_CREDENTIALS_explanation">插件将获准查询特定的网站及应用的证书。</string>
<string name="get_regular_version">获取更多的存储类型</string>
<string name="CertificateWarning">警告: 服务器证书验证失败: %1$ s。在您的设备上安装相应的根证书或请参阅设置 </string>
<string name="CertificateFailure">错误: 服务器证书验证失败!在您的设备上安装相应的根证书,或请参阅设置 </string>
<string name="export_fileformats_title">选择文件格式</string>
<string name="killed_by_os">对不起 Keepass2Android 被系统结束进程出于安全原因Keepass2Android 不在磁盘上存留证书,所以您需要重新打开您的数据库。注:出现该问题的几率极低。如果出现了,请给我发送我邮件至 crocoapps@gmail.com</string>
<string name="FileIsTemporarilyAvailable">该文件暂时仅供 Keepass2Android使用。</string>
<string name="FileIsReadOnly">您选择的文件是只读的。</string>
<string name="FileIsReadOnlyOnKitkat">在 Keepass2Android中由于 Android 4.4 + 的限制,您选定的文件是只读的 。</string>
<string name="CopyFileRequired">若要使用它,您必须将其复制到另一个位置。</string>
<string name="CopyFileRequiredForEditing">若要编辑它,必须将该文件复制到另一个位置。</string>
<string name="ClickOkToSelectLocation">单击确定以选择要复制文件的位置。</string>
<string name="FileReadOnlyTitle">数据库时只读的.</string>
<string name="FileReadOnlyMessagePre">Keepass2Android 已在只读模式打开当前数据库.</string>
<string name="ReadOnlyReason_PreKitKat">这看起来像你从一个外部app打开这个文件.这种方式不支持写入.如果你想修改数据库,请先关闭数据库并且选择修改数据库.然后如果可能的话从一个可用的选项打开这个文件.</string>
<string name="ReadOnlyReason_ReadOnlyFlag">已经设置了只读标记.如果你想修改数据库请解除这个标记.</string>
<string name="ReadOnlyReason_ReadOnlyKitKat">因为引入了android KitKat 的限制不能进行写入.如果你想对数据库进行修改,请先关闭数据库然后选择修改数据库.接下来使用文件系统选择器打开文件.</string>
<string name="ReadOnlyReason_LocalBackup">无法修改本地备份。你可以使用“数据库设置 - 导出数据库”将此备份导出至一个你可以重新打开的位置,之后便可进行修改。</string>
<string name="AddCustomIcon">从文件添加图标...</string>
<string name="CopyingFile">正在复制文件...</string>
<string name="DuplicateTitle">副本</string>
<string name="DefaultTemplate">进入数据库的标准</string>
<string name="TemplateGroupName">模板</string>
<string name="TemplateTitle_IdCard">身份卡</string>
<string name="TemplateField_IdCard_Name">名称</string>
<string name="TemplateField_IdCard_PlaceOfIssue">存放的位置</string>
<string name="TemplateField_IdCard_IssueDate">数据的位置</string>
<string name="TemplateTitle_EMail">电子邮箱</string>
<string name="TemplateField_EMail_EMail">电子邮箱地址</string>
<string name="TemplateTitle_WLan">无线局域网</string>
<string name="TemplateTitle_Notes">安全说明</string>
<string name="TemplateField_WLan_SSID">无线网络名称</string>
<string name="TemplateField_Number">数值</string>
<string name="TemplateField_CreditCard_CVV">验证码</string>
<string name="TemplateField_CreditCard_PIN">个人认证密码</string>
<string name="TemplateField_CreditCard_Owner">卡的持有者</string>
<string name="TemplateTitle_CreditCard">信用卡</string>
<string name="TemplateTitle_Membership">会员
</string>
<string name="ChangeLog_title">更新记录</string>
<string name="AskAddTemplatesTitle">增加模板</string>
<string name="AskAddTemplatesMessage">Keepass2Android包含了将电子邮箱账户,无线局域网密码,安全记录和别的更多的连入数据库模板.你想把这些加入你的数据库吗?如果你选择了否,你可以稍后在数据库设置中添加它们.</string>
<string name="AddTemplates_pref">添加模板到数据库中</string>
<string name="PreviewWarning">请注意这是一个预览版本可能会有一些缺陷如果您遇到“任何”意外请告诉我通过Google+ beta tester group或电子邮件</string>
<string name="Continue">继续</string>
<string name="NoFilenameWarning">您输入的 URI 不像是一个文件名。您确定这是一个有效的文件吗?</string>
<string name="FirstInvalidCompositeKeyError">复合密钥无效!请重试。</string>
<string name="RepeatedInvalidCompositeKeyHelp">无效的组合键!请按照下面的步骤解锁你的数据库:
•确保你输入了正确的密码.使用眼睛图标即可显示你输入的密码.
•确保你已经选择了正确的密码格式.确保使用的类型与创建的数据库匹配.
•确保你已经选择了正确的数据库文件.</string>
<string name="HintLocalBackupInvalidCompositeKey">
\n
• 提示:如果你认为数据库已损坏,或你在更改主密钥后把它忘了,你可以点击“%1$s”并选择本地备份以尝试最后一次成功打开的文件版本。</string>
<string name="HintLocalBackupOtherError">
\n
• 提示Keepass2Android已将最后一次成功打开版本保存到内部存储中。点击“%1$s”并选择本地备份以打开它。
</string>
<string name="CorruptDatabaseHelp">文件已损坏。\n
在这里是一些提示,这可能会有助于诊断问题: \n
• 如果您通过 USB (MTP 模式)复制该文件,请用类型 MyPhoneExplorer 这样的工具再试一次。在某些情况下MTP会 截断文件 \n
• 如果您无法在您的 PC 上相同的位置打开该文件,很有可能该文件实际上已损坏。请使用数据库备份。如果你假设 Keepass2Android 的文件已损坏,请联系开发者 \n
• 如果你仍然可以打开您的 PC 上的文件,请与支持人员联系。你可以尝试以不同的设置 (例如解压缩)将其保存到 PC然后重试再在 Keepass2Android 中打开。 </string>
<string name="DbUnlockedChannel_name">数据库已解锁</string>
<string name="DbUnlockedChannel_desc">数据库解锁通知</string>
<string name="DbQuicklockedChannel_name">快速解锁</string>
<string name="DbQuicklockedChannel_desc">数据库以快速解锁方式锁定通知</string>
<string name="EntryChannel_name">密码条目通知</string>
<string name="EntryChannel_desc">选定条目快速进入通知</string>
<string name="ErrorReportTitle">Keepass2Android: 出现一个错误。</string>
<string name="ErrorReportText">运行 Keepass2Android 时出现意外的错误。请通过允许应用程序发送错误报告来帮助我们进行修复。</string>
<string name="ErrorReportPromise">错误报告绝对不会包含数据库或主密码的任何内容。您可以在应用程序设置中禁用它们。</string>
<string name="ErrorReportEnable">启用</string>
<string name="ErrorReportDisable">禁用</string>
<string name="ErrorReportAsk">出错后询问</string>
<string name="ErrorReportPrefTitle">发送错误报告</string>
<string name="ShowKeyboardDuringFingerprintAuth">启用指纹扫描时显示软键盘用于密码输入.</string>
<string name="ChangeLog_1_05">
版本 1.05\n
* 采用Android 8的通知通道接受系统设置的控制\n
* 在通知中显示条目图标\n
* 采用Android 8的自适应图标在Android 7的启动器中显示为圆形图标\n
* 允许在解锁后自动进入搜索状态(详见设置)\n
* 更改在存储访问框架中的写文件方式修复了通过系统文件浏览器中选择Google云端硬盘文件时的文件更新问题\n
* 加入了一些说明文字避免误解\n
* 为成功打开的数据库实行本地备份,避免数据丢失\n
* 更新JSch以支持更多SSH加密协议\n
* 允许更改连接设置如修改WebDAV密码\n
* 加入Yubikey Neo的静态密码模式支持\n
* 允许禁用自动填充建议\n
* 修复logcat的数据泄露\n
* 错误修复\n
</string>
<string name="ChangeLog_1_04b">
版本 1.04b\n
* 华为设备用户在启用自动填充功能时不再崩溃。\n
</string>
<string name="ChangeLog_1_04">
1.04版\n
* 为 Android 8.0 及以上版本添加了自动填充服务。\n
* 升级了库、构建工具和目标 SDK 版本。\n
</string>
<string name="ChangeLog_1_03">
1.03版\n
* 根据 Google 的请求,移除了用于自动填充的辅助功能服务。请参阅密码权限设置以查找复现以前功能的插件。\n
* 重新添加了第三方应用作为存储选项的功能。\n
* 内置了无需将附加的图片传输至其他应用即可查看图片的图片查看器。\n
* 升级了 OkHttp 以修复一些连接问题\n
* 添加了 KeeTrayTOTP 条目的支持,现在支持了 Steam 条目。\n
</string>
<string name="ChangeLog_1_02">
版本 1.02\n
* 几项安全改进。非常感谢jean-baptiste.cayrou@thalesgroup.com 和 vincent.fargues@thalesgroup.com 的安全报告与合作 \n
* 支持KeyboardSwapPlugin (请参阅密码访问选项): 允许在非root设备上自动切换输入法。感谢来自XDA-Developers的Mishaal Rahman使这一功能成为可能。 \n
* 修复了最近几个Chrome版本的辅助功能服务 \n
* 修复了不必要的指纹数据清除 \n
* 修复了少量闪退 \n
* 更新了Dropbox SDK以确保未来的兼容性\n
* 删除通过Xamarin Insights的错误报告\n
* 更新了生成工具\n </string>
<string name="ChangeLog_1_01g">
版本 1.01-g\n
* 修复了离线使用时闪退的问题\n
* 修复了错误的FTP(S) 凭证编码\n
* 修复了使用OneDrive和较老的安卓版本时闪退的问题\n
* 在条目页显示本地时间\n
</string>
<string name="ChangeLog_1_01d">
版本 1.01-d\n
* 修复了OneDrive文件列表\n
* 允许忽略主机名称验证失败时的证书错误(不推荐用于生产环境)\n
* 修复了QuickUnlock不时失效尽管解码是正确的\n) </string>
<string name="ChangeLog_0_9_8c">
版本 0.9.8c\n
* 修复 Microsoft Live SDK使用 OneDrive 存取文件时用到)中的 SSL 漏洞\n
* 漏洞修复:上一版本附带了两个输入法项,其中一个不停崩溃\n </string>
<string name="ChangeLog_1_01">
版本 1.01\n
* 新增 KDBX-4 格式(兼容于 Keepass 2.35)的支持,包括 Argon2 密钥求导和 ChaCha20 加密。\n
* 实现 WebDav 文件存储,现可进行文件浏览并支持现代加密(如 SSL。\n
* 实现 FTP 文件存储,现可进行文件浏览并支持加密的 FTPS 。\n
* 更新 OneDrive SDK以前使用的 Live SDK 不再更新)。\n
* 更新 Dropbox SDK 第2版以前使用的第1版 SDK 已弃用)。\n
* 新增支持 OwnCloud 。\n
* 在打开本地文件之前提示存储权限。
</string>
<string name="ChangeLog_1_0_0e">
版本 1.0.0e\n
* 修复老旧的三星设备 Android 6 下的指纹解锁\n
* 添加 x86 设备原生支持\n
* 允许指纹扫描期间隐藏软键盘\n
* 构建系统更新
</string>
<string name="ChangeLog_1_0_0">版本 1.0.0\n
* 指纹解锁 (需要 Android 6.0 + 或一个三星设备) \n
* 添加自动填充服务 (需要 Android 5.0+) \n
* 添加支持登入数据库条目模板\n
* 添加\"脱机工作\"模式\n
* 允许复制多个登入数据库条目 \n
* 名字字段自动填充模式\n
* 允许从最近的文件删除项目 \n
* 在 Android 6.0运行时请求权限\n
* Bug 修复 (在内置键盘选择图标时) \n
* 包括了发送错误 reports 选项 \n
* 增加帮助消息在几个地方\n </string>
<string name="ChangeLog_0_9_9">
版本 0.9.9\n
* 重新设计用户界面,非常感谢 Stefano Pignataro (http://www.spstudio.at) 的支持! \n
* 允许添加自定义 icons\n
* 针对三星设备支持多窗口模式\n
* 增加加密轮为新 databases 的默认数量 \n
* 检查重复键的附加字段来避免丢失数据\n</string>
<string name="ChangeLog_0_9_9c">版本 0.9.9c\n
* 夜间主题来临\n
* 您可以安装其他图标包 (早期的 Windows 风格图标可以进行播放存储) \n
* 删除元素不放入回收箱时,增加了确认问题\n
* Bug 修复 (OTP 秘密编码错误显示,在一些地方的错误应用程序图标) \n</string>
<string name="ChangeLog_0_9_8b">版本 0.9.8b\n
* Bug 修复 (对于某些数据库保存失败导出到本地设备不能工作选择一些偏好选项时app崩溃) \n</string>
<string name="ChangeLog_0_9_8">
版本 0.9.8\n
* 支持 Storage Access Framework (KP2A 离线版具有写入SD卡或 Google 云端硬盘的能力)\n
* 尝试检测用户在输入 WebDAV URLs (指向目录而非文件) 时的错误 \n
* 密码字体变更\n
* 允许更改 Dropbox 账户\n
* 修复错误:现在可以记住一次性密码 (OTP)\n
</string>
<string name="ChangeLog_0_9_7b">
版本 0.9.7b\n
* 更新翻译\n
* 修复错误: 0.9.7 版本中密码字体丢失;“按名称排序”功能没有排序组\n
</string>
<string name="ChangeLog_0_9_7">
Version 0.9.7\n
* 支持修改 Keepass 1 (kdb) 数据库 (测试中!)\n
* 更好的方式来恢复之前的键盘(非 Root 设备也可使用)\n
* support for KeeChallenge with variable length challenges\n
* 阻止在快速解锁和密码界面截屏\n
* reverse sort order for Sort by Modification Date (now descending)\n
* bug fixes: Notes view now updated correctly after changes, Password views now hiding password correctly on (hopefully) all devices, fixed issue that allowed to add an entry twice, fixed issue with showing Duplicate UUID warning even after fixing the database\n
</string>
<string name="ChangeLog_0_9_6">
版本 0.9.6\n
* 允许导入密钥文件和本地的数据库文件到应用内部目录(请看设置)\n
* 支持不同的排序方式\n
* 优化自动切换键盘的配置\n
* 更新图标和界面, 由 Stefano Pignataro (http://www.spstudio.at) 设计\n
* 密码生成器记录最后的配置\n
* 为 Android 5 的锁屏界面设置通知可见性\n
* 当没有点击确认就离开应用时,清除主密码\n
* 修正部分设备无法设置输入语言的问题\n
* 修正 Root 设备自动切换键盘的问题\n
* 添加检查数据库的功能 (重复的 UUID\n
* 当检测到数据库修改后自动重新读取, 解决一个关于主密码的安全隐患\n
* 优化波兰语键盘, 修正键盘设置主题样式(感谢 Wiktor Ławski\n
</string>
<string name="ChangeLog_0_9_5"><b>Version 0.9.5</b>\n
*修正了文件浏览问题尤其是在Android 4.4中)\n
*修正了在Nexus 5手机的Android Lollipop版本中载入文件扩展名为.kbdkeepass1的问题\n
*增加了防止截屏/从当前运行的应用列表中隐藏的选项\n
*修正了与Google Drive服务的文件存储器(普通版)的问题\n
*允许密钥文件以经过审议的类型存储(普通版)\n
*更新了DropBox SDK使其包含了一个官方安全补丁程序普通版\n
*更新了构建工具--&gt;apk安装包大小增加:-(\n
我保证还会有更多的改变。但他们将在下次版本发布-抱歉。我也想让那些补丁尽快发布。</string>
<string name="ChangeLog_0_9_4"><b>版本 0.9.4</b>\n
* 添加插件指出:参阅设置查看如何获得插件!\n
* 二维码插件(扫描密码、以二维码方式显示密码、转移条目至其他装有 KP2A 的设备)\n
* InputStick 插件(通过蓝牙转移证书至电脑——需要 InputStick USB 棒)\n
* 第三方应用可以简单地实现查询 KP2A 证书。您是开发者吗?如果合适的话请添加此证书至您的应用!\n
* 添加一次性密码TOTP的支持兼容 KeeOTP 和 TrayTotp\n
* 当数据库开启时,本应用应该不再会被系统结束进程\n
- - -\n
* 允许当通过点击返回键离开本应用时,不会锁定数据库(参见设置)\n
* 允许在搜索结果中显示群组名\n
* 允许在搜索结果中添加上下文菜单,包含「导航到父级」选项\n
* 允许在输入视图中显示组名\n
感谢 Matthieu 开发的这些新功能!\n
- - -\n
* 支持 KeeChallenge通过 Yubikey NEO感谢 Ben Rush 实现本功能!\n
* 改进用户界面\n
* 修复云端硬盘的界面错误\n
* 允许隐藏「捐赠」选项\n
* 快速解锁图标可以在 Android 4.2 及更高版本中隐藏\n </string>
<string name="ChangeLog_0_9_3_r5"><b>Version 0.9.3 r5</b>\n
* 合并来自 Xamarin 的修复Keepass2Android 现在与 Android 4.4.2 上的 ART 兼容了!\n
* 错误修复:同步过程中的错误(刷新显示,正确检查 http 上的更改),此错误体现在 Android 2.x 设备上使用 Google Drive 和 SkyDrive时关闭数据库后清除剪贴板打开附件与键盘显示错误。\n
</string>
<string name="ChangeLog_0_9_3"><b>Version 0.9.3</b>\n
* 新键盘与很多改进。请参照设置—自定义。\n
* 支持只读 kdbKeepass 1 文件)支持。实验!\n
* 添加 SFTP 支持\n
* 添加在 ART 下错误问题的解决办法Android 4.4.2\n
* 修复错误\n
</string>
<string name="ChangeLog_0_9_2"><b>Version 0.9.2</b>\n
* 新增支持 OTP (与 OtpKeyProv 插件兼容)\n
* 通过 NFC 从 YubiKey NEO 获得 一次性密码 \n
* 几处界面改进\n
* 集成 Keepass 2.24 库\n
* 添加允许结束应用程序进程的选项(参见设置)\n
* 改进 SSL 证书验证\n
* 修复错误\n</string>
<string name="ChangeLog_0_9_1">* 改进 SkyDrive 的支持(仅限于 Keepass2Android 非离线版)\n
* 改进 Google Driver 的支持\n
* 添加 NTLM 的支持</string>
<string name="ChangeLog_0_9"><b>Version 0.9</b>\n
* 支持 Dropbox 和 Google Drive读/写数据库;只支持 Keepass2Android 通常版)\n
* 支持自定义文件管理器(基于 Android 文件选择器 由 HBA 开发)\n
* 改进创建数据库时的界面\n
* 包含自定义字体 DejaVu Sans Mono 用于显示密码\n
* 修复问题</string>
<string name="ChangeLog_0_8_6"><b>Version 0.8.6</b>\n
* 支持双鱼算法\n
* 允许编辑群组\n
* 允许移动的条目和群组\n
* QuickUnlock图标可设透明参见设置\n
* 修复错误</string>
<string name="ChangeLog_0_8_5"><b>Version 0.8.5</b>\n
* Remote files are stored in the local application cache to allow offline usage (including editing and later synchronization). See settings. \n
* Notification icon to visualize the lock-state of the database (see settings)\n
* Improved determination of lock-state in some situations\n
* Database files are loaded to memory while you are typing your password for increased loading speed (see settings)\n
* Entries can be added to root group\n
* Bug fixes (resolving reference fields, problems with keyboard on Italian an Chinese devices)</string>
<string name="ChangeLog_0_8_4"><b>Version 0.8.4</b>\n
* External database changes are detected and merged when saving\n
* Improved loading performance\n
* Improved search toolbar with suggestions\n
* New App logo!\n
* Added support for .kdbp format for faster loading/saving\n
* Improved editing of extra strings and hidden display when protected\n
Thanks to Alex Vallat for his code contributions!\n
Thanks to Niki Hüttner (www.close-cut.de) for the new logo!\n</string>
<string name="ChangeLog_0_8_3"><b>Version 0.8.3</b>\n
* Username/TAN index displayed in entry list (see settings)\n
* Entries can be created if search from browser doesn\'t return results\n
* KP2A keyboard provides possibility to search for credentials for current app\n
* App automatically closes after selecting an entry for use in keyboard\n
* Keyboard selection dialog automatically opens after search for URL (see settings)\n
* Placeholders in entry fields are replaced before copying (most placeholders supported)\n
* minor bug fixes</string>
<string name="ChangeLog_0_8_2"><b>Version 0.8.2</b>\n
* Support for Digest Authentication in WebDAV\n
* Bugfixes (OI File manager, Open URL)</string>
<string name="ChangeLog_0_8_1"><b>Version 0.8.1</b>\n
* KP2A Offline and \"Online\" can be installed both again\n
* Added new translations (thanks to all contributors!)</string>
<string name="ChangeLog_0_8"><b>Version 0.8</b>\n
* Improved user interface especially for Android 4.x devices\n
* Allow using deliberate file managers for selecting existing files\n
* Added safer way for opening attachments (through cache directory)\n
* fixed bugs in Edit activity\n
* probably introduced new bugs :-)</string>
<string name="ChangeLog_keptDonate">捐出一杯啤酒或别的来提供扩展的可能。</string>
<string name="ChangeLog_0_7"><b>Version 0.7</b>\n
* Increased loading speed: key transformations now 10x faster!\n
* Added Keepass2Android soft-keyboard: Switch to this keyboard for entering credentials. Shields you from clipboard-based password sniffers (disable old clipboard notifications in the options)\n
* Added option to donate a beer or something else (see menu)</string>
<string name="ChangeLog"><b>Version 0.6.2</b>\n
* Google Drive/Dropbox/... 集成: 使用官方 Google Drive 或者 Dropbox 程序并打开任何 .kdbx-file. 将在将来的版本出现.\n
* 改善搜索对话框 \n
* 改善分享URL子域名的搜索结果 \n
* 在菜单中添加反馈,评分和翻译此程序(哎,作者真讨厌)\n
\n
<b>版本 0.6.1</b>\n
* 检测数据库在后端是否有改动 (例如因为别的程序的同步造成的改动)\n
* 改善从浏览器搜索URL\n
* 当丢弃更改时显示确认对话框\n
\n
<b>版本 0.6</b>\n
Initial public release
</string>
<string-array name="clipboard_timeout_options">
<item>30秒</item>
<item>1分钟</item>
<item>5分钟</item>
<item>10 分钟</item>
<item>15 分钟</item>
<item>30 分钟</item>
<item>1 小时</item>
<item>从不</item>
</string-array>
<string-array name="export_fileformat_options">
<item>Keepass 2 数据库 (.kdbx)</item>
<item>不加密的 Keepass 2 XML (.xml)</item>
<item>不加密的 Keepass CSV (.csv)</item>
</string-array>
<string-array name="list_size_options">
<item></item>
<item></item>
<item></item>
</string-array>
<string-array name="design_options">
<item>白天模式</item>
<item>夜间模式</item>
</string-array>
<string name="design_title">设计</string>
<string-array name="ftp_encryption_modes">
<item>无加密 (FTP)</item>
<item>隐式加密 (FTP over TLS, FTPS)</item>
<item>显式加密 (FTP over TLS, FTPS)</item>
</string-array>
<string-array name="cred_remember_modes">
<item>不记得用户名和密码</item>
<item>仅记得用户名</item>
<item>记得用户名及密码</item>
</string-array>
<string-array name="password_modes">
<item>仅密码</item>
<item>密码 + 密钥文件</item>
<item>密码 + 一次性密码</item>
<item>密码 + 一次性密码 (恢复模式)</item>
<item>密码 + 挑战—响应</item>
<item>密码 + 挑战—响应(恢复模式)</item>
<item>密码 + 挑战-应答Keepass XC</item>
</string-array>
<string-array name="AcceptAllServerCertificates_options">
<item>忽略证书验证失败</item>
<item>在验证失败时发出警告</item>
<item>不接受无效的证书</item>
</string-array>
<string name="ClearClipboardWarning">请确认您的系统可以使用,否则请使用内置键盘。</string>
<string name="PluginDescription">为插件提供说明:</string>
<string name="autofill_hint">Keepass2Android 支持 Android 的自动填充功能,但看起来你还没有启用它。</string>
<string name="autofill_enable">启用自动填充</string>
<string name="autofill_enable_failed">抱歉,你的设备貌似不支持直接在应用内唤出系统设置。请亲自前往系统设置,启动自动填充服务。</string>
<string name="show_autofill_help">显示自动填充帮助</string>
<string name="autofill_sign_in_prompt">使用 Keepass2Android 填充</string>
<string name="invalid_link_association">无法关联 Web 域 %1$s 与应用程序 %2$s</string>
<string name="understand">我明白了</string>
<string name="dont_show_again">不再显示</string>
<string name="masterkey_infotext_head">你还记得你的主密码吗?</string>
<string name="masterkey_infotext_main">请注意,没有主密钥,你将无法打开数据库。不存在任何“重置”主密钥的方法。</string>
<string name="masterkey_infotext_fingerprint_note">另外需要注意的是指纹解锁是通过将主密钥保存在Android的安全存储中而实现的。安全存储会随时被Android删除例如当你在系统设置中添加了新指纹时。因此不要依赖指纹解锁请千万记住你的主密钥</string>
<string name="backup_infotext_head">你的数据库备份过了吗?</string>
<string name="backup_infotext_main">Keepass2Android将会在指定位置处保存一个密码数据文件。你确定在你手机丢失、失窃或文件遭到破坏和丢失的情况下你还能找到这个文件吗请确保你在安全的地方留有一份及时更新的数据备份</string>
<string name="backup_infotext_note">要立即创建备份,前往 %1$s &gt; %2$s &gt; %3$s。</string>
<string name="emergency_infotext_head">你准备好应对突发情况了吗?</string>
<string name="emergency_infotext_main">你是否考虑过,当你突然无法打开你的密码数据库时,该怎么办?万一你不幸发生事故,又该怎么办?你应该将主密钥托付给一个值得信任的人,以应对突发情况。除此以外的其他人都无法查看你的密码。</string>
</resources>

View File

@@ -82,7 +82,7 @@
<bool name="ShowUsernameInList_default">true</bool>
<bool name="ShowGroupnameInSearchResult_default">true</bool>
<string name="ViewDatabaseSecure_key">ViewDatabaseSecure</string>
<string name="ShowKeyboardWhileFingerprint_key">ShowKeyboardWhileFingerprint_key</string>
<string name="CloseDatabaseAfterFailedBiometricQuickUnlock_key">CloseDatabaseAfterFailedBiometricQuickUnlock_key</string>
<bool name="RememberRecentFiles_default">true</bool>
<string name="TrayTotp_SettingsField_key">TrayTotp_SettingsField_key</string>
<string name="TrayTotp_SeedField_key">TrayTotp_SeedField_key</string>

View File

@@ -779,7 +779,7 @@
<string name="EntryChannel_name">Entry notifications</string>
<string name="EntryChannel_desc">Notification to simplify access to the currently selected entry.</string>
<string name="ShowKeyboardDuringFingerprintAuth">Show soft keyboard for password input when biometric authentication is active.</string>
<string name="CloseDbAfterFailedAttempts">Close database after three failed biometric unlock attempts.</string>
<string-array name="ChangeLog_1_08">
<item>Add notification button for copying TOTP to clipboard</item>
@@ -1226,6 +1226,14 @@ Initial public release
<string name="emergency_infotext_main">Did you ever consider what happens if you are no longer able to access your password database? What if you have an accident? It is good practice to pass your master key to some trusted person for emergency cases. Nobody will have access to your passwords otherwise.</string>
<string name="no_secure_display">The currently valid display is not marked as secure. This means that screenshots might be taken by other apps. Keepass2Android is configured to display sensitive information on secure displays only. Please change to a secure display (e.g. by detaching an HDMI monitor) or change the app settings.</string>
<string name="switch_ime_text">Please activate the Keepass2Android keyboard.</string>
<string name="switch_ime_reopen">Retry</string>
<string name="AutofillWarning_title">Security Alert: Unrecognized domain/package link</string>
<string name="AutofillWarning_Intro">You are about to insert credentials for domain "%1$s" into the app with package name "%2$s".</string>
<string name="AutofillWarning_FillDomainInUntrustedApp">If you trust "%2$s" to belong to "%1$s" or you trust the app "%2$s" not to misuse the credentials (e.g. because it is a trusted browser app), it is ok to continue. If not, please cancel.</string>
<string name="AutofillWarning_continue">Security Alert: Unrecognized domain/package link</string>
</resources>

View File

@@ -1,4 +1,99 @@
<?xml version="1.0" encoding="utf-8" ?>
<autofill-service
xmlns:android="http://schemas.android.com/apk/res/android"
/>
>
<compatibility-package
android:name="com.android.chrome"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.chrome.beta"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.chrome.dev"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.chrome.canary"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.microsoft.emmx"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.opera.browser"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.opera.browser.beta"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.opera.mini.native"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.opera.mini.native.beta"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.sec.android.app.sbrowser"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.sec.android.app.sbrowser.beta"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="org.mozilla.fennec_aurora"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="org.mozilla.fennec_fdroid"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="org.mozilla.firefox"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="org.mozilla.firefox_beta"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="org.mozilla.fenix"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="org.mozilla.fenix.nightly"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="org.mozilla.reference.browser"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="org.mozilla.rocket"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.brave.browser"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.google.android.apps.chrome"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.google.android.apps.chrome_dev"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.yandex.browser"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="org.codeaurora.swe.browser"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.amazon.cloud9"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="mark.via.gp"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="org.bromite.bromite"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="org.chromium.chrome"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.kiwibrowser.browser"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.ecosia.android"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.vivaldi.browser"
android:maxLongVersionCode="10000000000"/>
</autofill-service>

View File

@@ -149,7 +149,7 @@ namespace keepass2android
createUrlEntry.Visibility = ViewStates.Visible;
createUrlEntry.Click += (sender, e) =>
{
GroupActivity.Launch(this, new CreateEntryThenCloseTask { Url = url, ShowUserNotifications = (AppTask as SelectEntryTask)?.ShowUserNotifications ?? true }, new ActivityLaunchModeRequestCode(0));
GroupActivity.Launch(this, new CreateEntryThenCloseTask { Url = url, ShowUserNotifications = (AppTask as SelectEntryTask)?.ShowUserNotifications ?? ShowUserNotificationsMode.Always }, new ActivityLaunchModeRequestCode(0));
Toast.MakeText(this, GetString(Resource.String.select_group_then_add, new Java.Lang.Object[] { GetString(Resource.String.add_entry) }), ToastLength.Long).Show();
};
}

View File

@@ -20,6 +20,9 @@ namespace keepass2android
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.switch_ime_activity_layout);
FindViewById<Button>(Resource.Id.btn_reopen).Click += (sender, args) => TrySwitchKeyboard();
FindViewById<Button>(Resource.Id.btn_cancel).Click += (sender, args) => Finish();
}
private string Kp2aInputMethodName
{
@@ -32,6 +35,11 @@ namespace keepass2android
{
base.OnResume();
TrySwitchKeyboard();
}
private void TrySwitchKeyboard()
{
var needsKeyboardSwitch = NeedsKeyboardSwitch();
if (needsKeyboardSwitch)
@@ -50,8 +58,6 @@ namespace keepass2android
if (!NeedsKeyboardSwitch()) Finish();
});
}, null, timeToWait, timeToWait);
}
else
Finish();

View File

@@ -2,6 +2,7 @@
using System.Linq;
using System.Text;
using Android.App;
using KeePassLib;
using KeePassLib.Utility;
using PluginTOTP;
@@ -12,18 +13,27 @@ namespace keepass2android
readonly ITotpPluginAdapter[] _pluginAdapters = new ITotpPluginAdapter[] { new TrayTotpPluginAdapter(), new KeeOtpPluginAdapter(), new KeeWebOtpPluginAdapter() };
public ITotpPluginAdapter TryGetAdapter(PwEntryOutput entry)
{
if (entry == null)
return null;
foreach (ITotpPluginAdapter adapter in _pluginAdapters)
{
TotpData totpData = adapter.GetTotpData(App.Kp2a.LastOpenedEntry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString()), Application.Context, false);
if (totpData.IsTotpEnry)
{
return adapter;
}
}
return null;
}
public void OnOpenEntry()
{
if (App.Kp2a.LastOpenedEntry == null)
return;
foreach (ITotpPluginAdapter adapter in _pluginAdapters)
{
TotpData totpData = adapter.GetTotpData(App.Kp2a.LastOpenedEntry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString()), Application.Context, false);
if (totpData.IsTotpEnry)
{
new UpdateTotpTimerTask(Application.Context, adapter).Run();
}
}
}
var adapter = TryGetAdapter(App.Kp2a.LastOpenedEntry);
if (adapter != null)
new UpdateTotpTimerTask(Application.Context, adapter).Run();
}
}
}

View File

@@ -541,15 +541,19 @@ namespace keepass2android
}
}
public static bool GetShowKeyboardDuringFingerprintUnlock(Context ctx)
{
return (PreferenceManager.GetDefaultSharedPreferences(ctx).GetBoolean(
ctx.GetString(Resource.String.ShowKeyboardWhileFingerprint_key), true));
}
public static bool GetCloseDatabaseAfterFailedBiometricQuickUnlock(Context ctx)
{
return (PreferenceManager.GetDefaultSharedPreferences(ctx).GetBoolean(
ctx.GetString(Resource.String.CloseDatabaseAfterFailedBiometricQuickUnlock_key), true));
}
public static void MoveBottomBarButtons(int btn1Id, int btn2Id, int bottomBarId, Activity context)
public static void MoveBottomBarButtons(int btn1Id, int btn2Id, int bottomBarId, Activity context)
{
var btn1 = context.FindViewById<Button>(btn1Id);
var btn2 = context.FindViewById<Button>(btn2Id);

View File

@@ -45,9 +45,13 @@ using keepass2android.database.edit;
using KeePassLib.Interfaces;
using KeePassLib.Utility;
#if !NoNet
#if !EXCLUDE_JAVAFILESTORAGE
using Android.Gms.Common;
using Keepass2android.Javafilestorage;
using GoogleDriveFileStorage = keepass2android.Io.GoogleDriveFileStorage;
using PCloudFileStorage = keepass2android.Io.PCloudFileStorage;
#endif
#endif
namespace keepass2android
{
@@ -97,10 +101,13 @@ namespace keepass2android
}
#endif
/// <summary>
/// Main implementation of the IKp2aApp interface for usage in the real app.
/// </summary>
public class Kp2aApp: IKp2aApp, ICacheSupervisor
public class Kp2aApp: IKp2aApp, ICacheSupervisor
{
public void Lock(bool allowQuickUnlock = true)
{
@@ -696,7 +703,7 @@ namespace keepass2android
#if !NoNet
new DropboxFileStorage(Application.Context, this),
new DropboxAppFolderFileStorage(Application.Context, this),
new GoogleDriveFileStorage(Application.Context, this),
GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(Application.Context)==ConnectionResult.Success ? new GoogleDriveFileStorage(Application.Context, this) : null,
new OneDriveFileStorage(Application.Context, this),
new OneDrive2FullFileStorage(),
new OneDrive2MyFilesFileStorage(),
@@ -710,7 +717,7 @@ namespace keepass2android
#endif
#endif
new LocalFileStorage(this)
};
}.Where(fs => fs != null).ToList();
}
return _fileStorages;
}
@@ -791,12 +798,13 @@ namespace keepass2android
return prefs.GetBoolean(Application.Context.GetString(Resource.String.CheckForDuplicateUuids_key), true);
}
}
#if !NoNet
public ICertificateErrorHandler CertificateErrorHandler
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
public ICertificateErrorHandler CertificateErrorHandler
{
get { return new CertificateErrorHandlerImpl(this); }
}
public class CertificateErrorHandlerImpl : Java.Lang.Object, Keepass2android.Javafilestorage.ICertificateErrorHandler

View File

@@ -348,7 +348,28 @@ namespace keepass2android
{
}
}
protected static bool GetBoolFromBundle(Bundle b, string key, bool defaultValue)
{
bool boolValue;
if (!Boolean.TryParse(b.GetString(key), out boolValue))
{
boolValue = defaultValue;
}
return boolValue;
}
protected static int GetIntFromBundle(Bundle b, string key, int defaultValue)
{
int intValue;
if (!Int32.TryParse(b.GetString(key), out intValue))
{
intValue = defaultValue;
}
return intValue;
}
}
/// <summary>
/// Implementation of AppTask for "no task currently active" (Null pattern)
@@ -474,50 +495,54 @@ namespace keepass2android
}
}
/// <summary>
/// User is about to select an entry for use in another app
/// </summary>
public class SelectEntryTask: AppTask
public enum ShowUserNotificationsMode
{
Never,
WhenTotp,
Always
}
/// <summary>
/// User is about to select an entry for use in another app
/// </summary>
public class SelectEntryTask: AppTask
{
public SelectEntryTask()
{
ShowUserNotifications = true;
ShowUserNotifications = ShowUserNotificationsMode.Always;
CloseAfterCreate = true;
}
ActivateKeyboard = true;
}
public const String ShowUserNotificationsKey = "ShowUserNotifications";
public bool ShowUserNotifications { get; set; }
public ShowUserNotificationsMode ShowUserNotifications { get; set; }
public const String CloseAfterCreateKey = "CloseAfterCreate";
public const String ActivateKeyboardKey = "ActivateKeyboard";
public bool CloseAfterCreate { get; set; }
public bool CloseAfterCreate { get; set; }
public bool ActivateKeyboard { get; set; }
public override void Setup(Bundle b)
public override void Setup(Bundle b)
{
ShowUserNotifications = GetBoolFromBundle(b, ShowUserNotificationsKey, true);
ShowUserNotifications = (ShowUserNotificationsMode) GetIntFromBundle(b, ShowUserNotificationsKey, (int)ShowUserNotificationsMode.Always);
CloseAfterCreate = GetBoolFromBundle(b, CloseAfterCreateKey, true);
}
ActivateKeyboard = GetBoolFromBundle(b, ActivateKeyboardKey, true);
}
private static bool GetBoolFromBundle(Bundle b, string key, bool defaultValue)
{
bool boolValue;
if (!Boolean.TryParse(b.GetString(key), out boolValue))
{
boolValue = defaultValue;
}
return boolValue;
}
public override IEnumerable<IExtra> Extras
public override IEnumerable<IExtra> Extras
{
get
{
yield return new StringExtra { Key = ShowUserNotificationsKey, Value = ShowUserNotifications.ToString() };
yield return new StringExtra { Key = ShowUserNotificationsKey, Value = ((int)ShowUserNotifications).ToString() };
yield return new StringExtra { Key = CloseAfterCreateKey, Value = CloseAfterCreate.ToString() };
}
yield return new StringExtra { Key = ActivateKeyboardKey, Value = ActivateKeyboard.ToString() };
}
}
public override void CompleteOnCreateEntryActivity(EntryActivity activity)
@@ -526,10 +551,11 @@ namespace keepass2android
if (ctx == null)
ctx = Application.Context;
if (ShowUserNotifications)
if ((ShowUserNotifications == ShowUserNotificationsMode.Always)
|| ((ShowUserNotifications == ShowUserNotificationsMode.WhenTotp) && new Kp2aTotp().TryGetAdapter(new PwEntryOutput(activity.Entry, App.Kp2a.CurrentDb)) != null))
{
//show the notifications
activity.StartNotificationsService(CloseAfterCreate);
activity.StartNotificationsService(ActivateKeyboard);
}
else
{
@@ -604,7 +630,7 @@ namespace keepass2android
{
public CreateEntryThenCloseTask()
{
ShowUserNotifications = true;
ShowUserNotifications = ShowUserNotificationsMode.Always;
}
public override bool CanActivateSearchViewOnStart
@@ -644,17 +670,13 @@ namespace keepass2android
public IList<string> ProtectedFieldsList { get; set; }
public bool ShowUserNotifications { get; set; }
public ShowUserNotificationsMode ShowUserNotifications { get; set; }
public override void Setup(Bundle b)
{
bool showUserNotification;
if (!Boolean.TryParse(b.GetString(ShowUserNotificationsKey), out showUserNotification))
{
showUserNotification = true; //default to true
}
ShowUserNotifications = showUserNotification;
ShowUserNotifications = (ShowUserNotificationsMode)GetIntFromBundle(b,ShowUserNotificationsKey, (int)ShowUserNotificationsMode.Always);
Url = b.GetString(UrlKey);
AllFields = b.GetString(AllFieldsKey);

View File

@@ -31,6 +31,7 @@ using Java.IO;
using KeePassLib.Serialization;
using Keepass2android.Pluginsdk;
using keepass2android.Io;
using Console = System.Console;
using Environment = Android.OS.Environment;
namespace keepass2android
@@ -302,6 +303,16 @@ namespace keepass2android
private void EditFileEntry(string filename, IOConnectionInfo newConnectionInfo)
{
try
{
App.Kp2a.GetFileStorage(newConnectionInfo);
}
catch (NoFileStorageFoundException)
{
Toast.MakeText(this, "Don't know how to handle " + newConnectionInfo.Path, ToastLength.Long).Show();
return;
}
_dbHelper.CreateFile(newConnectionInfo, _dbHelper.GetKeyFileForFile(filename), false);
_dbHelper.DeleteFile(filename);

View File

@@ -117,9 +117,6 @@
<Reference Include="System.Core" />
<Reference Include="Mono.Android" />
<Reference Include="System.Xml.Linq" />
<Reference Include="Xamarin.Jetbrains.Annotations, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Jetbrains.Annotations.13.0.0.1\lib\monoandroid90\Xamarin.Jetbrains.Annotations.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Kotlin.StdLib, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Kotlin.StdLib.1.3.50.1\lib\monoandroid90\Xamarin.Kotlin.StdLib.dll</HintPath>
</Reference>
@@ -809,10 +806,6 @@
<Folder Include="SupportLib\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BiometricBinding\BiometricBinding.csproj">
<Project>{2b1de455-bf8e-4f8a-87be-ae7ea354f3e4}</Project>
<Name>BiometricBinding</Name>
</ProjectReference>
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj">
<Project>{48574278-4779-4B3A-A9E4-9CF1BC285D0B}</Project>
<Name>JavaFileStorageBindings</Name>
@@ -1895,163 +1888,180 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentFTP">
<Version>27.1.3</Version>
<Version>32.4.3</Version>
</PackageReference>
<PackageReference Include="Microsoft.Bcl">
<Version>1.1.10</Version>
</PackageReference>
<PackageReference Include="Microsoft.Graph">
<Version>1.17.0</Version>
<Version>1.21.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.Graph.Auth">
<Version>1.0.0-preview.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.Identity.Client">
<Version>4.4.0</Version>
<Version>4.8.2</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Core.Common">
<Version>1.1.1.1</Version>
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Core.Runtime">
<Version>1.1.1.1</Version>
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.Common">
<Version>1.1.1.1</Version>
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.LiveData">
<Version>1.1.1.1</Version>
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.LiveData.Core">
<Version>1.1.1.1</Version>
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.Runtime">
<Version>1.1.1.1</Version>
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.ViewModel">
<Version>1.1.1.1</Version>
<Version>1.1.1.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Animated.Vector.Drawable">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Annotations">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.AsyncLayoutInflater">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Collections">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Compat">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CoordinaterLayout">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Core.UI">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Core.Utils">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CursorAdapter">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CustomTabs">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CustomView">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Design">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.DocumentFile">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.DrawerLayout">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Fragment">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Interpolator">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Loader">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.LocalBroadcastManager">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Media.Compat">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Print">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.SlidingPaneLayout">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.SwipeRefreshLayout">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Transition">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v13">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v4">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v7.CardView">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.VersionedParcelable">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.ViewPager">
<Version>28.0.0.1</Version>
<Version>28.0.0.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.AppCompat.Resources">
<Version>1.1.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.Biometric">
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.Browser">
<Version>1.0.0-preview02</Version>
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.Legacy.Support.V13">
<Version>1.0.0-preview02</Version>
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.Lifecycle.LiveData">
<Version>2.1.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.Migration">
<Version>1.0.0-preview05</Version>
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Build.Download">
<Version>0.4.2</Version>
<Version>0.8.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Google.Android.Material">
<Version>1.0.0-preview02</Version>
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.GooglePlayServices.Drive">
<Version>27.0.0</Version>
<Version>71.1600.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Jetbrains.Annotations">
<Version>13.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Kotlin.StdLib.Common">
<Version>1.3.50.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Kotlin.StdLib">
<Version>1.3.50.1</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\switch_ime_activity_layout.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Xamarin.Jetbrains.Annotations.13.0.0.1\build\monoandroid90\Xamarin.Jetbrains.Annotations.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Jetbrains.Annotations.13.0.0.1\build\monoandroid90\Xamarin.Jetbrains.Annotations.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Kotlin.StdLib.Common.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Kotlin.StdLib.Common.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.Common.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Kotlin.StdLib.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Kotlin.StdLib.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.targets'))" />
</Target>
<Import Project="..\packages\Xamarin.Jetbrains.Annotations.13.0.0.1\build\monoandroid90\Xamarin.Jetbrains.Annotations.targets" Condition="Exists('..\packages\Xamarin.Jetbrains.Annotations.13.0.0.1\build\monoandroid90\Xamarin.Jetbrains.Annotations.targets')" />
<Import Project="..\packages\Xamarin.Kotlin.StdLib.Common.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.Common.targets" Condition="Exists('..\packages\Xamarin.Kotlin.StdLib.Common.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.Common.targets')" />
<Import Project="..\packages\Xamarin.Kotlin.StdLib.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.targets" Condition="Exists('..\packages\Xamarin.Kotlin.StdLib.1.3.50.1\build\monoandroid90\Xamarin.Kotlin.StdLib.targets')" />
</Project>

View File

@@ -293,7 +293,8 @@ namespace keepass2android.search
case 0: // _ID
return Position.ToString(CultureInfo.InvariantCulture);
case 1: // SuggestColumnText1
return CurrentEntry.Strings.ReadSafe(PwDefs.TitleField);
string username = CurrentEntry.Strings.ReadSafe(PwDefs.UserNameField);
return CurrentEntry.Strings.ReadSafe(PwDefs.TitleField) + (string.IsNullOrWhiteSpace(username) ? "" : " ("+username+")");
case 2: // SuggestColumnText2
return Internationalise(_entriesWithContexts[Position].resultContext);
case 3: // SuggestColumnIcon1

View File

@@ -16,8 +16,13 @@ namespace keepass2android.services.AutofillBase
{
public interface IAutofillIntentBuilder
{
IntentSender GetAuthIntentSenderForResponse(Context context, string query, bool isManualRequest, bool autoReturnFromQuery);
IntentSender GetDisableIntentSenderForResponse(Context context, string query, bool isManualRequest, bool isDisable);
IntentSender GetAuthIntentSenderForResponse(Context context, string query, string queryDomain, string queryPackage,
bool isManualRequest, bool autoReturnFromQuery, AutofillServiceBase.DisplayWarning warning);
IntentSender GetAuthIntentSenderForWarning(Context context, string query, string queryDomain, string queryPackage, AutofillServiceBase.DisplayWarning warning);
IntentSender GetDisableIntentSenderForResponse(Context context, string query,
bool isManualRequest, bool isDisable);
Intent GetRestartAppIntent(Context context);
int AppIconResource { get; }
@@ -35,6 +40,44 @@ namespace keepass2android.services.AutofillBase
{
}
public static HashSet<string> CompatBrowsers = new HashSet<string>
{
"org.mozilla.firefox",
"org.mozilla.firefox_beta",
"com.microsoft.emmx",
"com.android.chrome",
"com.chrome.beta",
"com.android.browser",
"com.brave.browser",
"com.opera.browser",
"com.opera.browser.beta",
"com.opera.mini.native",
"com.chrome.dev",
"com.chrome.canary",
"com.google.android.apps.chrome",
"com.google.android.apps.chrome_dev",
"com.yandex.browser",
"com.sec.android.app.sbrowser",
"com.sec.android.app.sbrowser.beta",
"org.codeaurora.swe.browser",
"com.amazon.cloud9",
"mark.via.gp",
"org.bromite.bromite",
"org.chromium.chrome",
"com.kiwibrowser.browser",
"com.ecosia.android",
"com.opera.mini.native.beta",
"org.mozilla.fennec_aurora",
"org.mozilla.fennec_fdroid",
"com.qwant.liberty",
"com.opera.touch",
"org.mozilla.fenix",
"org.mozilla.fenix.nightly",
"org.mozilla.reference.browser",
"org.mozilla.rocket",
"org.torproject.torbrowser",
"com.vivaldi.browser",
};
public override void OnFillRequest(FillRequest request, CancellationSignal cancellationSignal, FillCallback callback)
{
@@ -52,7 +95,7 @@ namespace keepass2android.services.AutofillBase
Log.Warn(CommonUtil.Tag, "Cancel autofill not implemented yet.");
};
// Parse AutoFill data in Activity
string query = null;
StructureParser.AutofillTargetId query = null;
var parser = new StructureParser(this, structure);
try
{
@@ -74,16 +117,44 @@ namespace keepass2android.services.AutofillBase
{
var responseBuilder = new FillResponse.Builder();
var entryDataset = AddEntryDataset(query, parser);
Dataset entryDataset = null;
if (query.IncompatiblePackageAndDomain == false)
{
//domain and package are compatible. Use Domain if available and package otherwise. Can fill without warning.
entryDataset = BuildEntryDataset(query.DomainOrPackage, query.WebDomain, query.PackageName, autofillIds, parser, DisplayWarning.None);
}
else
{
//domain or package are incompatible. Don't show the entry. (Tried to do so first but behavior was not consistent)
//entryDataset = BuildEntryDataset(query.WebDomain, query.WebDomain, query.PackageName, autofillIds, parser, DisplayWarning.FillDomainInUntrustedApp);
}
bool hasEntryDataset = entryDataset != null;
if (entryDataset != null)
responseBuilder.AddDataset(entryDataset);
AddQueryDataset(query, isManual, autofillIds, responseBuilder, !hasEntryDataset);
AddDisableDataset(query, autofillIds, responseBuilder, isManual);
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(GetString(Resource.String.OfferSaveCredentials_key), true))
responseBuilder.SetSaveInfo(new SaveInfo.Builder(parser.AutofillFields.SaveType,
parser.AutofillFields.GetAutofillIds()).Build());
if (query.WebDomain != null)
AddQueryDataset(query.WebDomain,
query.WebDomain, query.PackageName,
isManual, autofillIds, responseBuilder, !hasEntryDataset, query.IncompatiblePackageAndDomain ? DisplayWarning.FillDomainInUntrustedApp : DisplayWarning.None);
else
AddQueryDataset(query.PackageNameWithPseudoSchema,
query.WebDomain, query.PackageName,
isManual, autofillIds, responseBuilder, !hasEntryDataset, DisplayWarning.None);
AddDisableDataset(query.DomainOrPackage, autofillIds, responseBuilder, isManual);
if (PreferenceManager.GetDefaultSharedPreferences(this)
.GetBoolean(GetString(Resource.String.OfferSaveCredentials_key), true))
{
if (!CompatBrowsers.Contains(parser.PackageId))
{
responseBuilder.SetSaveInfo(new SaveInfo.Builder(parser.AutofillFields.SaveType,
parser.AutofillFields.GetAutofillIds()).Build());
}
}
callback.OnSuccess(responseBuilder.Build());
}
@@ -93,22 +164,57 @@ namespace keepass2android.services.AutofillBase
}
}
private Dataset AddEntryDataset(string query, StructureParser parser)
private Dataset BuildEntryDataset(string query, string queryDomain, string queryPackage, AutofillId[] autofillIds, StructureParser parser,
DisplayWarning warning)
{
var filledAutofillFieldCollection = GetSuggestedEntry(query);
if (filledAutofillFieldCollection == null)
return null;
int partitionIndex = AutofillHintsHelper.GetPartitionIndex(parser.AutofillFields.FocusedAutofillCanonicalHints.FirstOrDefault());
FilledAutofillFieldCollection partitionData = AutofillHintsHelper.FilterForPartition(filledAutofillFieldCollection, partitionIndex);
return AutofillHelper.NewDataset(this, parser.AutofillFields, partitionData, IntentBuilder);
if (warning == DisplayWarning.None)
{
//can return an actual dataset
int partitionIndex = AutofillHintsHelper.GetPartitionIndex(parser.AutofillFields.FocusedAutofillCanonicalHints.FirstOrDefault());
FilledAutofillFieldCollection partitionData = AutofillHintsHelper.FilterForPartition(filledAutofillFieldCollection, partitionIndex);
return AutofillHelper.NewDataset(this, parser.AutofillFields, partitionData, IntentBuilder);
}
else
{
//return an "auth" dataset (actually for just warning the user in case domain/package dont match)
var sender = IntentBuilder.GetAuthIntentSenderForWarning(this, query, queryDomain, queryPackage, warning);
var datasetName = filledAutofillFieldCollection.DatasetName;
if (datasetName == null)
return null;
RemoteViews presentation = AutofillHelper.NewRemoteViews(PackageName, datasetName, AppNames.LauncherIcon);
var datasetBuilder = new Dataset.Builder(presentation);
datasetBuilder.SetAuthentication(sender);
//need to add placeholders so we can directly fill after ChooseActivity
foreach (var autofillId in autofillIds)
{
datasetBuilder.SetValue(autofillId, AutofillValue.ForText("PLACEHOLDER"));
}
return datasetBuilder.Build();
}
}
protected abstract FilledAutofillFieldCollection GetSuggestedEntry(string query);
private void AddQueryDataset(string query, bool isManual, AutofillId[] autofillIds, FillResponse.Builder responseBuilder, bool autoReturnFromQuery)
public enum DisplayWarning
{
var sender = IntentBuilder.GetAuthIntentSenderForResponse(this, query, isManual, autoReturnFromQuery);
None,
FillDomainInUntrustedApp, //display a warning that the user is filling credentials for a domain inside an app not marked as trusted browser
}
private void AddQueryDataset(string query, string queryDomain, string queryPackage, bool isManual, AutofillId[] autofillIds, FillResponse.Builder responseBuilder, bool autoReturnFromQuery, DisplayWarning warning)
{
var sender = IntentBuilder.GetAuthIntentSenderForResponse(this, query, queryDomain, queryPackage, isManual, autoReturnFromQuery, warning);
RemoteViews presentation = AutofillHelper.NewRemoteViews(PackageName,
GetString(Resource.String.autofill_sign_in_prompt), AppNames.LauncherIcon);
@@ -174,13 +280,13 @@ namespace keepass2android.services.AutofillBase
responseBuilder.AddDataset(datasetBuilder.Build());
}
private bool CanAutofill(string query, bool isManual)
private bool CanAutofill(StructureParser.AutofillTargetId query, bool isManual)
{
if (query == "androidapp://android" || query == "androidapp://" + this.PackageName)
if (query.PackageNameWithPseudoSchema == "androidapp://android" || query.PackageNameWithPseudoSchema == "androidapp://" + this.PackageName)
return false;
if (!isManual)
{
var isQueryDisabled = IsQueryDisabled(query);
var isQueryDisabled = IsQueryDisabled(query.DomainOrPackage);
if (isQueryDisabled)
return false;
}
@@ -206,7 +312,7 @@ namespace keepass2android.services.AutofillBase
}
var parser = new StructureParser(this, structure);
string query = parser.ParseForSave();
var query = parser.ParseForSave();
try
{
HandleSaveRequest(parser, query);
@@ -219,7 +325,7 @@ namespace keepass2android.services.AutofillBase
}
protected abstract void HandleSaveRequest(StructureParser parser, string query);
protected abstract void HandleSaveRequest(StructureParser parser, StructureParser.AutofillTargetId query);
public override void OnConnected()

View File

@@ -12,6 +12,7 @@ using Java.Util;
using keepass2android.services.AutofillBase.model;
using System.Collections.Generic;
using System.Linq;
using AlertDialog = Android.App.AlertDialog;
namespace keepass2android.services.AutofillBase
{
@@ -22,8 +23,12 @@ namespace keepass2android.services.AutofillBase
public static string ExtraQueryString => "EXTRA_QUERY_STRING";
public static string ExtraQueryPackageString => "EXTRA_QUERY_PACKAGE_STRING";
public static string ExtraQueryDomainString => "EXTRA_QUERY_DOMAIN_STRING";
public static string ExtraUseLastOpenedEntry => "EXTRA_USE_LAST_OPENED_ENTRY"; //if set to true, no query UI is displayed. Can be used to just show a warning
public static string ExtraIsManualRequest => "EXTRA_IS_MANUAL_REQUEST";
public static string ExtraAutoReturnFromQuery => "EXTRA_AUTO_RETURN_FROM_QUERY";
public static string ExtraDisplayWarning => "EXTRA_DISPLAY_WARNING";
public int RequestCodeQuery => 6245;
@@ -46,12 +51,56 @@ namespace keepass2android.services.AutofillBase
RestartApp();
return;
}
if (Intent.HasExtra(ExtraDisplayWarning))
{
AutofillServiceBase.DisplayWarning warning =
(AutofillServiceBase.DisplayWarning)Intent.GetIntExtra(ExtraDisplayWarning, (int)AutofillServiceBase.DisplayWarning.None);
if (warning != AutofillServiceBase.DisplayWarning.None)
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.SetTitle(this.GetString(Resource.String.AutofillWarning_title));
var i = GetQueryIntent(requestedUrl, Intent.GetBooleanExtra(ExtraAutoReturnFromQuery, true));
StartActivityForResult(i, RequestCodeQuery);
builder.SetMessage(
GetString(Resource.String.AutofillWarning_Intro, new Java.Lang.Object[] { Intent.GetStringExtra(ExtraQueryDomainString), Intent.GetStringExtra(ExtraQueryPackageString) })
+ " " +
this.GetString(Resource.String.AutofillWarning_FillDomainInUntrustedApp, new Java.Lang.Object[] { Intent.GetStringExtra(ExtraQueryDomainString), Intent.GetStringExtra(ExtraQueryPackageString) }));
builder.SetPositiveButton(this.GetString(Resource.String.Continue),
(dlgSender, dlgEvt) =>
{
Proceed();
});
builder.SetNegativeButton(this.GetString(Resource.String.cancel), (dlgSender, dlgEvt) =>
{
Finish();
});
Dialog dialog = builder.Create();
dialog.Show();
return;
}
}
Proceed();
}
protected abstract Intent GetQueryIntent(string requestedUrl, bool autoReturnFromQuery);
private void Proceed()
{
string requestedUrl = Intent.GetStringExtra(ExtraQueryString);
var i = GetQueryIntent(requestedUrl, Intent.GetBooleanExtra(ExtraAutoReturnFromQuery, true), Intent.GetBooleanExtra(ExtraUseLastOpenedEntry, false));
if (i == null)
{
//GetQueryIntent returns null if no query is required
ReturnSuccess();
}
else
StartActivityForResult(i, RequestCodeQuery);
}
protected abstract Intent GetQueryIntent(string requestedUrl, bool autoReturnFromQuery, bool useLastOpenedEntry);
protected void RestartApp()
{
@@ -100,15 +149,24 @@ namespace keepass2android.services.AutofillBase
if (requestCode == RequestCodeQuery)
{
if (resultCode == ExpectedActivityResult)
OnSuccess(GetDataset(data), Intent.GetBooleanExtra(ExtraIsManualRequest, false));
ReturnSuccess();
else
OnFailure();
Finish();
{
OnFailure();
Finish();
}
}
}
private void ReturnSuccess()
{
OnSuccess(GetDataset(), Intent.GetBooleanExtra(ExtraIsManualRequest, false));
Finish();
}
protected virtual Result ExpectedActivityResult
{
get { return Result.Ok; }
@@ -117,7 +175,7 @@ namespace keepass2android.services.AutofillBase
/// <summary>
/// Creates the FilledAutofillFieldCollection from the intent returned from the query activity
/// </summary>
protected abstract FilledAutofillFieldCollection GetDataset(Intent data);
protected abstract FilledAutofillFieldCollection GetDataset();
public abstract IAutofillIntentBuilder IntentBuilder { get; }

View File

@@ -28,6 +28,8 @@ namespace keepass2android.services.AutofillBase
private PublicSuffixRuleCache domainSuffixParserCache;
public FilledAutofillFieldCollection ClientFormData { get; set; }
public string PackageId { get; set; }
public StructureParser(Context context, AssistStructure structure)
{
mContext = context;
@@ -36,24 +38,52 @@ namespace keepass2android.services.AutofillBase
domainSuffixParserCache = new PublicSuffixRuleCache(context);
}
public string ParseForFill(bool isManual)
public class AutofillTargetId
{
public string PackageName { get; set; }
public string PackageNameWithPseudoSchema
{
get { return "androidapp://" + PackageName; }
}
public string WebDomain { get; set; }
/// <summary>
/// If PackageName and WebDomain are not compatible (by DAL or because PackageName is a trusted browser in which case we treat all domains as "compatible"
/// we need to issue a warning. If we would fill credentials for the package, a malicious website could try to get credentials for the app.
/// If we would fill credentials for the domain, a malicious app could get credentials for the domain.
/// </summary>
public bool IncompatiblePackageAndDomain { get; set; }
public string DomainOrPackage
{
get
{
return WebDomain ?? PackageNameWithPseudoSchema;
}
}
}
public AutofillTargetId ParseForFill(bool isManual)
{
return Parse(true, isManual);
}
public string ParseForSave()
public AutofillTargetId ParseForSave()
{
return Parse(false, true);
}
/// <summary>
/// Traverse AssistStructure and add ViewNode metadata to a flat list.
/// </summary>
/// <returns>The parse.</returns>
/// <param name="forFill">If set to <c>true</c> for fill.</param>
/// <param name="isManualRequest"></param>
string Parse(bool forFill, bool isManualRequest)
{
/// <summary>
/// Traverse AssistStructure and add ViewNode metadata to a flat list.
/// </summary>
/// <returns>The parse.</returns>
/// <param name="forFill">If set to <c>true</c> for fill.</param>
/// <param name="isManualRequest"></param>
AutofillTargetId Parse(bool forFill, bool isManualRequest)
{
AutofillTargetId result = new AutofillTargetId();
CommonUtil.logd("Parsing structure for " + Structure.ActivityComponent);
var nodes = Structure.WindowNodeCount;
ClientFormData = new FilledAutofillFieldCollection();
@@ -63,6 +93,7 @@ namespace keepass2android.services.AutofillBase
for (int i = 0; i < nodes; i++)
{
var node = Structure.GetWindowNodeAt(i);
var view = node.RootViewNode;
ParseLocked(forFill, isManualRequest, view, ref webDomain);
}
@@ -78,23 +109,33 @@ namespace keepass2android.services.AutofillBase
{
passwordFields = _editTextsWithoutHint.Where(HasPasswordHint).ToList();
}
foreach (var passwordField in passwordFields)
{
var usernameField = _editTextsWithoutHint.TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault();
if (usernameField != null)
{
usernameFields.Add(usernameField);
}
}
//for some pages with two-step login, we don't see a password field and don't display the autofill for non-manual requests. But if the user forces autofill,
//let's assume it is a username field:
if (isManualRequest && !passwordFields.Any() && _editTextsWithoutHint.Count == 1)
{
usernameFields.Add(_editTextsWithoutHint.First());
usernameFields = _editTextsWithoutHint.Where(HasUsernameHint).ToList();
if (usernameFields.Any() == false)
{
foreach (var passwordField in passwordFields)
{
var usernameField = _editTextsWithoutHint
.TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault();
if (usernameField != null)
{
usernameFields.Add(usernameField);
}
}
}
if (usernameFields.Any() == false)
{
//for some pages with two-step login, we don't see a password field and don't display the autofill for non-manual requests. But if the user forces autofill,
//let's assume it is a username field:
if (isManualRequest && !passwordFields.Any() && _editTextsWithoutHint.Count == 1)
{
usernameFields.Add(_editTextsWithoutHint.First());
}
}
}
//force focused fields to be included in autofill fields when request was triggered manually. This allows to fill fields which are "off" or don't have a hint (in case there are hints)
@@ -131,32 +172,47 @@ namespace keepass2android.services.AutofillBase
}
String packageName = Structure.ActivityComponent.PackageName;
result.WebDomain = webDomain;
result.PackageName = Structure.ActivityComponent.PackageName;
if (!string.IsNullOrEmpty(webDomain))
{
bool valid = Kp2aDigitalAssetLinksDataSource.Instance.IsValid(mContext, webDomain, packageName);
if (!valid)
{
CommonUtil.loge($"DAL verification failed for {packageName}/{webDomain}");
webDomain = null;
}
result.IncompatiblePackageAndDomain = !Kp2aDigitalAssetLinksDataSource.Instance.IsValid(mContext, webDomain, result.PackageName);
if (result.IncompatiblePackageAndDomain)
{
CommonUtil.loge($"DAL verification failed for {result.PackageName}/{result.WebDomain}");
}
}
if (string.IsNullOrEmpty(webDomain))
else
{
webDomain = "androidapp://" + packageName;
CommonUtil.logd("no web domain. Using package name.");
}
return webDomain;
result.IncompatiblePackageAndDomain = false;
}
return result;
}
private static bool HasPasswordHint(AssistStructure.ViewNode f)
private static readonly HashSet<string> _passwordHints = new HashSet<string> { "password","passwort" };
private static bool HasPasswordHint(AssistStructure.ViewNode f)
{
return (f.IdEntry?.ToLowerInvariant().Contains("password") ?? false)
|| (f.Hint?.ToLowerInvariant().Contains("password") ?? false);
}
return ContainsAny(f.IdEntry, _passwordHints) ||
ContainsAny(f.Hint, _passwordHints);
}
private static bool IsInputTypeClass(InputTypes inputType, InputTypes inputTypeClass)
private static readonly HashSet<string> _usernameHints = new HashSet<string> { "email","e-mail","username" };
private static bool HasUsernameHint(AssistStructure.ViewNode f)
{
return ContainsAny(f.IdEntry, _usernameHints) ||
ContainsAny(f.Hint, _usernameHints);
}
private static bool ContainsAny(string value, IEnumerable<string> terms)
{
if (string.IsNullOrWhiteSpace(value))
{
return false;
}
var lowerValue = value.ToLowerInvariant();
return terms.Any(t => lowerValue.Contains(t));
}
private static bool IsInputTypeClass(InputTypes inputType, InputTypes inputTypeClass)
{
if (!InputTypes.MaskClass.HasFlag(inputTypeClass))
throw new Exception("invalid inputTypeClas");
@@ -198,8 +254,13 @@ namespace keepass2android.services.AutofillBase
void ParseLocked(bool forFill, bool isManualRequest, AssistStructure.ViewNode viewNode, ref string validWebdomain)
{
String webDomain = viewNode.WebDomain;
if ((PackageId == null) && (!string.IsNullOrWhiteSpace(viewNode.IdPackage)) &&
(viewNode.IdPackage != "android"))
{
PackageId = viewNode.IdPackage;
}
DomainName outDomain;
DomainName outDomain;
if (DomainName.TryParse(webDomain, domainSuffixParserCache, out outDomain))
{
webDomain = outDomain.RegisterableDomainName;
@@ -224,9 +285,13 @@ namespace keepass2android.services.AutofillBase
if (viewHints != null && viewHints.Length == 1 && viewHints.First() == "off" && viewNode.IsFocused &&
isManualRequest)
viewHints[0] = "on";
CommonUtil.logd("viewHints=" + viewHints);
CommonUtil.logd("class=" + viewNode.ClassName);
CommonUtil.logd("tag=" + (viewNode?.HtmlInfo?.Tag ?? "(null)"));
if (viewHints != null && viewHints.Any())
{
CommonUtil.logd("viewHints=" + viewHints);
CommonUtil.logd("class=" + viewNode.ClassName);
CommonUtil.logd("tag=" + (viewNode?.HtmlInfo?.Tag ?? "(null)"));
}
if (viewNode?.HtmlInfo?.Tag == "input")
{
foreach (var p in viewNode.HtmlInfo.Attributes)

View File

@@ -102,6 +102,9 @@ namespace keepass2android
private int CreateCombinedNotification(string entryName, Bitmap entryIcon)
{
Kp2aLog.Log("Create Combined Notifications: " + _hasKeyboard + " " + _hasPassword + " " + _hasUsername +
" " + _hasTotp);
if ((!_hasUsername) && (!_hasPassword) && (!_hasKeyboard) && (!_hasTotp))
return 0;
@@ -142,6 +145,8 @@ namespace keepass2android
private int CreateSeparateNotifications(string entryName, Bitmap entryIcon)
{
Kp2aLog.Log("Create Separate Notifications: " + _hasKeyboard + " " + _hasPassword + " " + _hasUsername +
" " + _hasTotp);
int numNotifications = 0;
if (_hasPassword)
{
@@ -347,8 +352,8 @@ namespace keepass2android
if (intent.Action == Intents.ShowNotification)
{
//first time opening the entry -> bring up the notifications
bool closeAfterCreate = intent.GetBooleanExtra(EntryActivity.KeyCloseAfterCreate, false);
DisplayAccessNotifications(entry, closeAfterCreate, searchUrl);
bool activateKeyboard = intent.GetBooleanExtra(EntryActivity.KeyActivateKeyboard, false);
DisplayAccessNotifications(entry, activateKeyboard, searchUrl);
}
else //UpdateKeyboard
{
@@ -429,7 +434,7 @@ namespace keepass2android
public void DisplayAccessNotifications(PwEntryOutput entry, bool closeAfterCreate, string searchUrl)
public void DisplayAccessNotifications(PwEntryOutput entry, bool activateKeyboard, string searchUrl)
{
var hadKeyboardData = ClearNotifications();
@@ -483,7 +488,7 @@ namespace keepass2android
{
//switch rooted
bool onlySwitchOnSearch = prefs.GetBoolean(GetString(Resource.String.OpenKp2aKeyboardAutomaticallyOnlyAfterSearch_key), false);
if (closeAfterCreate || (!onlySwitchOnSearch))
if (activateKeyboard || (!onlySwitchOnSearch))
{
ActivateKp2aKeyboard();
}
@@ -492,7 +497,7 @@ namespace keepass2android
{
//if the app is about to be closed again (e.g. after searching for a URL and returning to the browser:
// automatically bring up the Keyboard selection dialog
if ((closeAfterCreate) && prefs.GetBoolean(GetString(Resource.String.OpenKp2aKeyboardAutomatically_key), Resources.GetBoolean(Resource.Boolean.OpenKp2aKeyboardAutomatically_default)))
if ((activateKeyboard) && prefs.GetBoolean(GetString(Resource.String.OpenKp2aKeyboardAutomatically_key), Resources.GetBoolean(Resource.Boolean.OpenKp2aKeyboardAutomatically_default)))
{
ActivateKp2aKeyboard();
}
@@ -510,6 +515,7 @@ namespace keepass2android
if (_numElementsToWaitFor == 0)
{
Kp2aLog.Log("Stopping CopyToClipboardService, created empty notification");
StopSelf();
return;
}
@@ -620,9 +626,11 @@ namespace keepass2android
public void OnWaitElementDeleted(int itemId)
{
Kp2aLog.Log("Wait element deleted: " + itemId);
_numElementsToWaitFor--;
if (_numElementsToWaitFor <= 0)
{
Kp2aLog.Log("Stopping CopyToClipboardService, no more elements");
StopSelf();
}
if ((itemId == NotifyKeyboard) || (itemId == NotifyCombined))
@@ -818,8 +826,18 @@ namespace keepass2android
//must be enabled in settings first
Toast.MakeText(this, Resource.String.please_activate_keyboard, ToastLength.Long).Show();
Intent settingsIntent = new Intent(Android.Provider.Settings.ActionInputMethodSettings);
settingsIntent.SetFlags(ActivityFlags.NewTask);
StartActivity(settingsIntent);
try
{
settingsIntent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ExcludeFromRecents);
StartActivity(settingsIntent);
}
catch (Exception e)
{
//seems like on Huawei devices this call can fail.
Kp2aLog.LogUnexpectedError(e);
Toast.MakeText(this, "Failed to switch keyboard.", ToastLength.Long).Show();
}
}
else
{
@@ -835,9 +853,20 @@ namespace keepass2android
}
if (mustUseHelperActivity)
{
Intent switchImeIntent = new Intent(this, typeof(SwitchImeActivity));
switchImeIntent.SetFlags(ActivityFlags.NewTask);
StartActivity(switchImeIntent);
try
{
Intent switchImeIntent = new Intent(this, typeof(SwitchImeActivity));
switchImeIntent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ExcludeFromRecents);
StartActivity(switchImeIntent);
}
catch (Exception e)
{
//seems like on Huawei devices this call can fail.
Kp2aLog.LogUnexpectedError(e);
Toast.MakeText(this, "Failed to switch keyboard.", ToastLength.Long).Show();
}
}
else
{
@@ -889,7 +918,7 @@ namespace keepass2android
if (App.Kp2a.LastOpenedEntry == null)
{
Intent i = new Intent(context, typeof(AppKilledInfo));
i.SetFlags(ActivityFlags.ClearTask | ActivityFlags.NewTask);
i.SetFlags(ActivityFlags.ClearTask | ActivityFlags.NewTask | ActivityFlags.ExcludeFromRecents);
context.StartActivity(i);
return;
}

View File

@@ -24,20 +24,24 @@ namespace keepass2android.services.Kp2aAutofill
Permission = "keepass2android." + AppNames.PackagePart + ".permission.Kp2aChooseAutofill")]
public class ChooseForAutofillActivity : ChooseForAutofillActivityBase
{
protected override Intent GetQueryIntent(string requestedUrl, bool autoReturnFromQuery)
protected override Intent GetQueryIntent(string requestedUrl, bool autoReturnFromQuery, bool useLastOpenedEntry)
{
if (useLastOpenedEntry && (App.Kp2a.LastOpenedEntry?.SearchUrl == requestedUrl))
{
return null;
}
//launch FileSelectActivity (which is root of the stack (exception: we're even below!)) with the appropriate task.
//will return the results later
Intent i = new Intent(this, typeof(SelectCurrentDbActivity));
//don't show user notifications when an entry is opened.
var task = new SearchUrlTask() { UrlToSearchFor = requestedUrl, ShowUserNotifications = false, AutoReturnFromQuery = autoReturnFromQuery };
var task = new SearchUrlTask() { UrlToSearchFor = requestedUrl, ShowUserNotifications = ShowUserNotificationsMode.WhenTotp, AutoReturnFromQuery = autoReturnFromQuery, ActivateKeyboard = false };
task.ToIntent(i);
return i;
}
protected override Result ExpectedActivityResult => KeePass.ExitCloseAfterTaskComplete;
protected override FilledAutofillFieldCollection GetDataset(Intent data)
protected override FilledAutofillFieldCollection GetDataset()
{
if (App.Kp2a.CurrentDb==null || (App.Kp2a.QuickLocked))
return null;

View File

@@ -15,7 +15,7 @@ using AutofillServiceBase = keepass2android.services.AutofillBase.AutofillServic
namespace keepass2android.services
{
[Service(Label = AppNames.AppName, Permission=Manifest.Permission.BindAutofillService)]
[Service(Label = AppNames.AppName, Permission=Manifest.Permission.BindAutofillService)]
[IntentFilter(new [] {"android.service.autofill.AutofillService"})]
[MetaData("android.autofill", Resource = "@xml/autofillservice")]
[Register("keepass2android.services.Kp2aAutofillService")]
@@ -39,11 +39,11 @@ namespace keepass2android.services
return null;
}
protected override void HandleSaveRequest(StructureParser parser, string query)
protected override void HandleSaveRequest(StructureParser parser, StructureParser.AutofillTargetId query)
{
var intent = new Intent(this, typeof(SelectCurrentDbActivity));
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTop | ActivityFlags.SingleTop);
Dictionary<string, string> outputFields = new Dictionary<string, string>();
foreach (var p in parser.ClientFormData.HintMap)
@@ -53,7 +53,7 @@ namespace keepass2android.services
}
if (query != null)
outputFields.TryAdd(PwDefs.UrlField, query);
outputFields.TryAdd(PwDefs.UrlField, query.WebDomain);
JSONObject jsonOutput = new JSONObject(outputFields);
var jsonOutputStr = jsonOutput.ToString();

View File

@@ -15,16 +15,33 @@ namespace keepass2android.services
class Kp2aAutofillIntentBuilder: IAutofillIntentBuilder
{
public IntentSender GetAuthIntentSenderForResponse(Context context, string query, bool isManualRequest, bool autoReturnFromQuery)
public IntentSender GetAuthIntentSenderForResponse(Context context, string query, string queryDomain, string queryPackage,
bool isManualRequest, bool autoReturnFromQuery, AutofillServiceBase.DisplayWarning warning)
{
Intent intent = new Intent(context, typeof(ChooseForAutofillActivity));
intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryString, query);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryDomainString, queryDomain);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryPackageString, queryPackage);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraIsManualRequest, isManualRequest);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraAutoReturnFromQuery, autoReturnFromQuery);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraDisplayWarning, (int)warning);
return PendingIntent.GetActivity(context, 0, intent, PendingIntentFlags.CancelCurrent).IntentSender;
}
public IntentSender GetDisableIntentSenderForResponse(Context context, string query, bool isManualRequest, bool isDisable)
public IntentSender GetAuthIntentSenderForWarning(Context context, string query, string queryDomain, string queryPackage,
AutofillServiceBase.DisplayWarning warning)
{
Intent intent = new Intent(context, typeof(ChooseForAutofillActivity));
intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryString, query);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryDomainString, queryDomain);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryPackageString, queryPackage);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraDisplayWarning, (int)warning);
intent.PutExtra(ChooseForAutofillActivityBase.ExtraUseLastOpenedEntry, true);
return PendingIntent.GetActivity(context, 0, intent, PendingIntentFlags.CancelCurrent).IntentSender;
}
public IntentSender GetDisableIntentSenderForResponse(Context context, string query,
bool isManualRequest, bool isDisable)
{
Intent intent = new Intent(context, typeof(DisableAutofillForQueryActivity));
intent.PutExtra(ChooseForAutofillActivityBase.ExtraQueryString, query);

View File

@@ -235,8 +235,11 @@ namespace keepass2android
var dbname = kpDatabase.Name;
if (String.IsNullOrEmpty(dbname))
{
//todo: if paranoid ("don't remember recent files") return "***"
dbname = App.Kp2a.GetFileStorage(kpDatabase.IOConnectionInfo).GetFilenameWithoutPathAndExt(kpDatabase.IOConnectionInfo);
//if paranoid ("don't remember recent files")return "***"
if (!App.Kp2a.GetBooleanPreference(PreferenceKey.remember_keyfile))
return "***";
dbname = UrlUtil.StripExtension(
UrlUtil.GetFileName(App.Kp2a.GetFileStorage(kpDatabase.IOConnectionInfo).GetDisplayName(kpDatabase.IOConnectionInfo)));
}
if (displayString != "")
displayString = displayString + ", ";

View File

@@ -44,8 +44,6 @@ namespace keepass2android.view
get { return base.Activated; }
set
{
Log.Debug("KP2A", "Setting activated = " + value);
if (value)
{
FindViewById(Resource.Id.icon).Visibility = ViewStates.Invisible;