Compare commits
17 Commits
1.08b-r0
...
1.07b-r0-o
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2ca846093 | ||
|
|
38cee50f34 | ||
|
|
d45fd99235 | ||
|
|
05eea4aae1 | ||
|
|
8468049935 | ||
|
|
7cef6c8566 | ||
|
|
98f2a139e9 | ||
|
|
832d3b3a95 | ||
|
|
37867634cd | ||
|
|
d9713f8e18 | ||
|
|
c583b58cb9 | ||
|
|
bfeaf5dbf5 | ||
|
|
0907fa5685 | ||
|
|
ff8dc76c75 | ||
|
|
0b09e2790f | ||
|
|
781350aa5f | ||
|
|
9716130336 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -169,4 +169,3 @@ 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
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,6 +1,9 @@
|
||||
[submodule "src/SamsungPass"]
|
||||
path = src/SamsungPass
|
||||
url = https://github.com/PhilippC/Xamarin-Samsung-Pass.git
|
||||
[submodule "src/netftpandroid"]
|
||||
path = src/netftpandroid
|
||||
url = https://github.com/PhilippC/netftpandroid.git
|
||||
[submodule "src/java/argon2/phc-winner-argon2"]
|
||||
path = src/java/argon2/phc-winner-argon2
|
||||
url = https://github.com/P-H-C/phc-winner-argon2
|
||||
|
||||
@@ -77,10 +77,6 @@ The KP2A keyboard is meant to quickly "paste" or "type" values from your databas
|
||||
## Is it safe to store my kdbx file in the cloud?
|
||||
While it may happen that someone gets access to your kdbx file in the cloud, there is still no need to worry: the purpose of encryption is to protect the data even in case someone gets the kdbx file! As long as you are using a safe master key, you're safe! [Key files](https://keepass.info/help/base/keys.html#keyfiles) can help with securing the database even more.
|
||||
|
||||
## Doesn't Keepass2Android create automatic backups?
|
||||
Yes and no. Yes: Keepass2Android stores the last successfully opened file as a read-only backup locally on the phone (unless you disable this is in the settings). This should make sure that even if the file gets destroyed during a save operation or gets deleted by accident, you should always have a version that can be opened. (Don't mix this up with the internal file cache which is not meant as a backup and can easily be overwritten even with a corrupt file. This internal file cache is meant for providing writable access even when the original file is not reachable, e.g. when you're offline.)
|
||||
No: The local backup has two shortcomings: It is only one backup and does not allow to revert to older versions. So if you deleted an entry from the database, it might be deleted in the local backup soon as well. The even more important shortcoming is that it is just a local backup. It won't help when your phone gets lost or broken. Please create additional backups on seperate storage!
|
||||
|
||||
## How do I backup the database?
|
||||
If you have stored your database on the cloud, you might rely on your cloud storage providers backups. Make sure they allow you to revert to older revisions in case the file gets corrupted for some reason.
|
||||
If you are working with a local database file, make sure you create regular backups. I suggest you have an aumotated mechanism, e.g. with FolderSync (Lite) which can copy local files from your device to other locations, e.g. your PC in a local network. You can also use USB or tools like MyPhoneExploror to transfer data to your PC. Or, you use a removable storage like an SD card which you keep in a safe place after making the backup.
|
||||
|
||||
@@ -54,7 +54,7 @@ Please also add a few strings in your resource files (e.g. strings.xml) with the
|
||||
These strings will be displayed to the user when KP2A asks if access should be granted.
|
||||
|
||||
## Modifying the entry view
|
||||
You can add menu options for the full entry or for individual fields of the entry when displayed to the user. This is done, for example, by the QR plugin ([https://play.google.com/store/apps/details?id=keepass2android.plugin.qr](https://play.google.com/store/apps/details?id=keepass2android.plugin.qr)).
|
||||
You can add menu options for the full entry or for individual fields of the entry when displayed to the user. This is done, for example, by the QR plugin ([https://play.google.com/store/apps/details?id=keepass2android.plugin.qr](https___play.google.com_store_apps_details_id=keepass2android.plugin.qr)).
|
||||
In addition, it is even possible to add new fields or modify existing fields. Please see the sample plugin "PluginA" in the KP2A repository for a simple example on how to do this:
|
||||
[https://keepass2android.codeplex.com/SourceControl/latest#src/java/PluginA/src/keepass2android/plugina/PluginAActionReceiver.java](https://keepass2android.codeplex.com/SourceControl/latest#src/java/PluginA/src/keepass2android/plugina/PluginAActionReceiver.java)
|
||||
|
||||
|
||||
@@ -13,10 +13,9 @@ Beta-releases can be obtained by opting in to the [Beta testing channel](https:/
|
||||
# How can I contribute?
|
||||
* Help to translate Keepass2Android into your language or improve translations at [our Crowdin page](http://crowdin.net/project/keepass2android)
|
||||
* Add features by [creating a plugin](How-to-create-a-plug-in_.md) or creating a pull request. You might want to contact me before you start working so I can coordinate efforts.
|
||||
* [Become a GitHub sponsor to boost 🚀 development](https://github.com/sponsors/PhilippC)
|
||||
* [Make a donation](http://philipp.crocoll.net/donate.php)
|
||||
|
||||
# How do I learn more?
|
||||
Please see the [documentation](Documentation.md).
|
||||
|
||||
[](https://www.bitrise.io/app/43a23ab54dee9f7e)
|
||||
[](https://www.bitrise.io/app/43a23ab54dee9f7e)
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
|
||||
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
|
||||
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
||||
BIN
src/JavaFileStorageBindings/Jars/okhttp-3.9.0.jar
Normal file
BIN
src/JavaFileStorageBindings/Jars/okhttp-3.9.0.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/JavaFileStorageBindings/Jars/okhttp-digest-1.7.jar
Normal file
BIN
src/JavaFileStorageBindings/Jars/okhttp-digest-1.7.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/JavaFileStorageBindings/Jars/okio-1.13.0.jar
Normal file
BIN
src/JavaFileStorageBindings/Jars/okio-1.13.0.jar
Normal file
Binary file not shown.
Binary file not shown.
@@ -13,7 +13,6 @@
|
||||
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
|
||||
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
|
||||
<AndroidClassParser>class-parse</AndroidClassParser>
|
||||
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -85,6 +84,9 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PCloudBindings\PCloudBindings.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\okhttp-digest-1.7.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\msa-auth-0.8.6\classes-msa-auth.jar" />
|
||||
</ItemGroup>
|
||||
@@ -139,19 +141,16 @@
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\jackson-core-2.7.4.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\okhttp-3.9.0.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\okio-1.13.0.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedJar Include="Jars\dropbox-core-sdk-3.1.1.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\gson-2.8.1.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\okhttp-4.2.2.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\okio-2.2.2.jar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\okhttp-digest-2.0.jar" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -12,7 +12,6 @@
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
|
||||
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
|
||||
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29418.71
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2010
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassLib2Android", "KeePassLib2Android\KeePassLib2Android.csproj", "{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}"
|
||||
EndProject
|
||||
@@ -13,8 +13,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kp2aBusinessLogic", "Kp2aBu
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TwofishCipher", "TwofishCipher\TwofishCipher.csproj", "{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JavaFileStorageBindings", "JavaFileStorageBindings\JavaFileStorageBindings.csproj", "{48574278-4779-4B3A-A9E4-9CF1BC285D0B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AndroidFileChooserBinding", "AndroidFileChooserBinding\AndroidFileChooserBinding.csproj", "{3C0F7FE5-639F-4422-A087-8B26CF862D1B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KP2AKdbLibraryBinding", "KP2AKdbLibraryBinding\KP2AKdbLibraryBinding.csproj", "{70D3844A-D9FA-4A64-B205-A84C6A822196}"
|
||||
@@ -109,8 +107,8 @@ Global
|
||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
|
||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
|
||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
|
||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||
@@ -187,8 +185,8 @@ Global
|
||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
|
||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
|
||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
|
||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
|
||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||
@@ -205,8 +203,8 @@ Global
|
||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
|
||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
|
||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
|
||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
|
||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||
@@ -223,8 +221,8 @@ Global
|
||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
|
||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
|
||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
|
||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
|
||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||
|
||||
@@ -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,17 +872,8 @@ namespace KeePassLib.Serialization
|
||||
pb = pb8;
|
||||
}
|
||||
long lSec = MemUtil.BytesToInt64(pb);
|
||||
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;
|
||||
}
|
||||
}
|
||||
return new DateTime(lSec * TimeSpan.TicksPerSecond, DateTimeKind.Utc);
|
||||
}
|
||||
else
|
||||
{
|
||||
string str = ReadString(xr);
|
||||
|
||||
@@ -375,16 +375,13 @@ namespace KeePassLib.Serialization
|
||||
|
||||
// See also KeePassKdb2x3.Export (KDBX 3.1 export module)
|
||||
uint minVersionForKeys = m_pwDatabase.MasterKey.UserKeys.Select(key => key.GetMinKdbxVersion()).Max();
|
||||
|
||||
uint minRequiredVersion = Math.Max(minVersionForKeys, m_uFileVersion); //don't save a version lower than what we read
|
||||
|
||||
|
||||
|
||||
AesKdf kdfAes = new AesKdf();
|
||||
if(!kdfAes.Uuid.Equals(m_pwDatabase.KdfParameters.KdfUuid))
|
||||
return Math.Max(FileVersion32, minRequiredVersion);
|
||||
return Math.Max(FileVersion32, minVersionForKeys);
|
||||
|
||||
if(m_pwDatabase.PublicCustomData.Count > 0)
|
||||
return Math.Max(FileVersion32, minRequiredVersion);
|
||||
return Math.Max(FileVersion32, minVersionForKeys);
|
||||
|
||||
|
||||
|
||||
@@ -404,9 +401,9 @@ namespace KeePassLib.Serialization
|
||||
gh(m_pwDatabase.RootGroup);
|
||||
m_pwDatabase.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh);
|
||||
if(bCustomData)
|
||||
return Math.Max(FileVersion32, minRequiredVersion);
|
||||
return Math.Max(FileVersion32, minVersionForKeys);
|
||||
|
||||
return Math.Max(FileVersion32_3, minRequiredVersion); ; // KDBX 3.1 is sufficient
|
||||
return Math.Max(FileVersion32_3, minVersionForKeys); ; // KDBX 3.1 is sufficient
|
||||
}
|
||||
|
||||
private void ComputeKeys(out byte[] pbCipherKey, int cbCipherKey,
|
||||
|
||||
@@ -11,7 +11,7 @@ using KeePassLib.Keys;
|
||||
using KeePassLib.Serialization;
|
||||
using keepass2android.Io;
|
||||
using KeePassLib.Interfaces;
|
||||
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
|
||||
#if !NoNet
|
||||
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 && !EXCLUDE_JAVAFILESTORAGE
|
||||
#if !NoNet
|
||||
ICertificateErrorHandler CertificateErrorHandler { get; }
|
||||
|
||||
|
||||
|
||||
@@ -270,7 +270,7 @@ namespace keepass2android.Io
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
else return false;
|
||||
else throw new Exception("couldn't move to first result element: " + (cursor == null) + uri.ToString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -333,13 +333,12 @@ namespace keepass2android.Io
|
||||
|
||||
public void CommitWrite()
|
||||
{
|
||||
ParcelFileDescriptor fileDescriptor = _ctx.ContentResolver.OpenFileDescriptor(Android.Net.Uri.Parse(_path), "rwt");
|
||||
ParcelFileDescriptor fileDescriptor = _ctx.ContentResolver.OpenFileDescriptor(Android.Net.Uri.Parse(_path), "w");
|
||||
|
||||
using (var outputStream = new FileOutputStream(fileDescriptor.FileDescriptor))
|
||||
{
|
||||
byte[] data = _memoryStream.ToArray();
|
||||
|
||||
outputStream.Write(data);
|
||||
outputStream.Write(data, 0, data.Length);
|
||||
outputStream.Close();
|
||||
}
|
||||
fileDescriptor.Close();
|
||||
|
||||
@@ -3,12 +3,12 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.FtpClient;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Preferences;
|
||||
using FluentFTP;
|
||||
using KeePassLib;
|
||||
using KeePassLib.Serialization;
|
||||
using KeePassLib.Utility;
|
||||
@@ -17,6 +17,73 @@ namespace keepass2android.Io
|
||||
{
|
||||
public class NetFtpFileStorage: IFileStorage
|
||||
{
|
||||
class RetryConnectFtpClient : FtpClient
|
||||
{
|
||||
protected override FtpClient CloneConnection()
|
||||
{
|
||||
RetryConnectFtpClient conn = new RetryConnectFtpClient();
|
||||
|
||||
conn.m_isClone = true;
|
||||
|
||||
foreach (PropertyInfo prop in GetType().GetProperties())
|
||||
{
|
||||
object[] attributes = prop.GetCustomAttributes(typeof(FtpControlConnectionClone), true);
|
||||
|
||||
if (attributes != null && attributes.Length > 0)
|
||||
{
|
||||
prop.SetValue(conn, prop.GetValue(this, null), null);
|
||||
}
|
||||
}
|
||||
|
||||
// always accept certficate no matter what because if code execution ever
|
||||
// gets here it means the certificate on the control connection object being
|
||||
// cloned was already accepted.
|
||||
conn.ValidateCertificate += new FtpSslValidation(
|
||||
delegate(FtpClient obj, FtpSslValidationEventArgs e)
|
||||
{
|
||||
e.Accept = true;
|
||||
});
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
private static T DoInRetryLoop<T>(Func<T> func)
|
||||
{
|
||||
double timeout = 30.0;
|
||||
double timePerRequest = 1.0;
|
||||
var startTime = DateTime.Now;
|
||||
while (true)
|
||||
{
|
||||
var attemptStartTime = DateTime.Now;
|
||||
try
|
||||
{
|
||||
return func();
|
||||
}
|
||||
catch (System.Net.Sockets.SocketException e)
|
||||
{
|
||||
if ((e.ErrorCode != 10061) || (DateTime.Now > startTime.AddSeconds(timeout)))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
double secondsSinceAttemptStart = (DateTime.Now - attemptStartTime).TotalSeconds;
|
||||
if (secondsSinceAttemptStart < timePerRequest)
|
||||
{
|
||||
Thread.Sleep(TimeSpan.FromSeconds(timePerRequest - secondsSinceAttemptStart));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void Connect()
|
||||
{
|
||||
DoInRetryLoop(() =>
|
||||
{
|
||||
base.Connect();
|
||||
return true;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public struct ConnectionSettings
|
||||
{
|
||||
public FtpEncryptionMode EncryptionMode {get; set; }
|
||||
@@ -80,8 +147,9 @@ namespace keepass2android.Io
|
||||
|
||||
public NetFtpFileStorage(Context context, ICertificateValidationHandler app)
|
||||
{
|
||||
_app = app;
|
||||
_app = app;
|
||||
traceStream = new MemoryStream();
|
||||
FtpTrace.AddListener(new System.Diagnostics.TextWriterTraceListener(traceStream));
|
||||
|
||||
}
|
||||
|
||||
@@ -104,9 +172,9 @@ namespace keepass2android.Io
|
||||
{
|
||||
using (FtpClient client = GetClient(ioc))
|
||||
{
|
||||
string localPath = IocToLocalPath(ioc);
|
||||
string localPath = IocToUri(ioc).PathAndQuery;
|
||||
if (client.DirectoryExists(localPath))
|
||||
client.DeleteDirectory(localPath);
|
||||
client.DeleteDirectory(localPath, true);
|
||||
else
|
||||
client.DeleteFile(localPath);
|
||||
}
|
||||
@@ -137,8 +205,7 @@ namespace keepass2android.Io
|
||||
{
|
||||
var settings = ConnectionSettings.FromIoc(ioc);
|
||||
|
||||
FtpClient client = new FtpClient();
|
||||
client.RetryAttempts = 3;
|
||||
FtpClient client = new RetryConnectFtpClient();
|
||||
if ((settings.Username.Length > 0) || (settings.Password.Length > 0))
|
||||
client.Credentials = new NetworkCredential(settings.Username, settings.Password);
|
||||
else
|
||||
@@ -183,22 +250,20 @@ namespace keepass2android.Io
|
||||
path = path.Substring(settings.Length + 1);
|
||||
|
||||
}
|
||||
Kp2aLog.Log("FTP: IocToUri out = " + scheme + "://" + path);
|
||||
return new Uri(scheme + "://" + path);
|
||||
return new Uri(scheme + "://" + path);
|
||||
}
|
||||
|
||||
private string IocPathFromUri(IOConnectionInfo baseIoc, string uri)
|
||||
private string IocPathFromUri(IOConnectionInfo baseIoc, Uri uri)
|
||||
{
|
||||
string basePath = baseIoc.Path;
|
||||
string basePath = baseIoc.Path;
|
||||
int schemeLength = basePath.IndexOf("://", StringComparison.Ordinal);
|
||||
string scheme = basePath.Substring(0, schemeLength);
|
||||
basePath = basePath.Substring(schemeLength + 3);
|
||||
string baseSettings = basePath.Substring(0, basePath.IndexOf(ConnectionSettings.SettingsPostFix, StringComparison.Ordinal));
|
||||
basePath = basePath.Substring(baseSettings.Length+1);
|
||||
string baseHost = basePath.Substring(0, basePath.IndexOf("/", StringComparison.Ordinal));
|
||||
string result = scheme + "://" + baseSettings + ConnectionSettings.SettingsPostFix + baseHost + uri; //TODO does this contain Query?
|
||||
return result;
|
||||
}
|
||||
return scheme + "://" + baseSettings + ConnectionSettings.SettingsPostFix + baseHost + uri.AbsolutePath; //TODO does this contain Query?
|
||||
}
|
||||
|
||||
|
||||
public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion)
|
||||
@@ -216,12 +281,9 @@ namespace keepass2android.Io
|
||||
try
|
||||
{
|
||||
using (var cl = GetClient(ioc))
|
||||
{
|
||||
var memStream = new MemoryStream();
|
||||
cl.OpenRead(IocToLocalPath(ioc), FtpDataType.Binary, 0).CopyTo(memStream);
|
||||
memStream.Seek(0, SeekOrigin.Begin);
|
||||
return memStream;
|
||||
}
|
||||
{
|
||||
return cl.OpenRead(IocToUri(ioc).PathAndQuery, FtpDataType.Binary, 0);
|
||||
}
|
||||
}
|
||||
catch (FtpCommandException ex)
|
||||
{
|
||||
@@ -268,7 +330,7 @@ namespace keepass2android.Io
|
||||
{
|
||||
using (var client = GetClient(ioc))
|
||||
{
|
||||
client.CreateDirectory(IocToLocalPath(GetFilePath(ioc, newDirName)));
|
||||
client.CreateDirectory(IocToUri(GetFilePath(ioc, newDirName)).PathAndQuery);
|
||||
}
|
||||
}
|
||||
catch (FtpCommandException ex)
|
||||
@@ -277,19 +339,14 @@ namespace keepass2android.Io
|
||||
}
|
||||
}
|
||||
|
||||
public static string IocToLocalPath(IOConnectionInfo ioc)
|
||||
{
|
||||
return WebUtility.UrlDecode(IocToUri(ioc).PathAndQuery);
|
||||
}
|
||||
|
||||
public IEnumerable<FileDescription> ListContents(IOConnectionInfo ioc)
|
||||
public IEnumerable<FileDescription> ListContents(IOConnectionInfo ioc)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var client = GetClient(ioc))
|
||||
using (var client = GetClient(ioc))
|
||||
{
|
||||
List<FileDescription> files = new List<FileDescription>();
|
||||
foreach (FtpListItem item in client.GetListing(IocToLocalPath(ioc),
|
||||
foreach (FtpListItem item in client.GetListing(IocToUri(ioc).PathAndQuery,
|
||||
FtpListOption.Modify | FtpListOption.Size | FtpListOption.DerefLinks))
|
||||
{
|
||||
|
||||
@@ -303,7 +360,7 @@ namespace keepass2android.Io
|
||||
DisplayName = item.Name,
|
||||
IsDirectory = true,
|
||||
LastModified = item.Modified,
|
||||
Path = IocPathFromUri(ioc, item.FullName)
|
||||
Path = IocPathFromUri(ioc, new Uri(item.FullName))
|
||||
});
|
||||
break;
|
||||
case FtpFileSystemObjectType.File:
|
||||
@@ -314,7 +371,7 @@ namespace keepass2android.Io
|
||||
DisplayName = item.Name,
|
||||
IsDirectory = false,
|
||||
LastModified = item.Modified,
|
||||
Path = IocPathFromUri(ioc, item.FullName),
|
||||
Path = IocPathFromUri(ioc, new Uri(item.FullName)),
|
||||
SizeInBytes = item.Size
|
||||
});
|
||||
break;
|
||||
@@ -339,10 +396,10 @@ namespace keepass2android.Io
|
||||
//is it very inefficient to connect for each description?
|
||||
|
||||
using (FtpClient client = GetClient(ioc))
|
||||
{
|
||||
|
||||
|
||||
string path = IocToLocalPath(ioc);
|
||||
{
|
||||
|
||||
var uri = IocToUri(ioc);
|
||||
string path = uri.PathAndQuery;
|
||||
if (!client.FileExists(path) && (!client.DirectoryExists(path)))
|
||||
throw new FileNotFoundException();
|
||||
var fileDesc = new FileDescription()
|
||||
@@ -454,7 +511,7 @@ namespace keepass2android.Io
|
||||
{
|
||||
using (var client = GetClient(ioc))
|
||||
{
|
||||
return client.OpenWrite(IocToLocalPath(ioc));
|
||||
return client.OpenWrite(IocToUri(ioc).PathAndQuery);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -523,7 +580,7 @@ namespace keepass2android.Io
|
||||
{
|
||||
|
||||
_client = _fileStorage.GetClient(_ioc, false);
|
||||
_stream = _client.OpenWrite(NetFtpFileStorage.IocToLocalPath(_iocTemp));
|
||||
_stream = _client.OpenWrite(NetFtpFileStorage.IocToUri(_iocTemp).PathAndQuery);
|
||||
return _stream;
|
||||
}
|
||||
catch (FtpCommandException ex)
|
||||
@@ -538,11 +595,22 @@ namespace keepass2android.Io
|
||||
{
|
||||
Android.Util.Log.Debug("NETFTP","connected: " + _client.IsConnected.ToString());
|
||||
_stream.Close();
|
||||
_stream.Dispose();
|
||||
_client.GetReply();
|
||||
Android.Util.Log.Debug("NETFTP", "connected: " + _client.IsConnected.ToString());
|
||||
|
||||
_client.MoveFile(NetFtpFileStorage.IocToLocalPath(_iocTemp),
|
||||
NetFtpFileStorage.IocToLocalPath(_ioc));
|
||||
//make sure target file does not exist:
|
||||
//try
|
||||
{
|
||||
if (_client.FileExists(NetFtpFileStorage.IocToUri(_ioc).PathAndQuery))
|
||||
_client.DeleteFile(NetFtpFileStorage.IocToUri(_ioc).PathAndQuery);
|
||||
|
||||
}
|
||||
//catch (FtpCommandException)
|
||||
{
|
||||
//TODO get a new clien? might be stale
|
||||
}
|
||||
|
||||
_client.Rename(NetFtpFileStorage.IocToUri(_iocTemp).PathAndQuery,
|
||||
NetFtpFileStorage.IocToUri(_ioc).PathAndQuery);
|
||||
|
||||
}
|
||||
catch (FtpCommandException ex)
|
||||
|
||||
@@ -204,7 +204,6 @@ namespace keepass2android.Io
|
||||
private readonly string _specialFolder;
|
||||
public IGraphServiceClient client;
|
||||
public OneDrive2ItemLocation<OneDrive2PrefixContainerType> itemLocation;
|
||||
public bool verbose;
|
||||
|
||||
public PathItemBuilder(string specialFolder)
|
||||
{
|
||||
@@ -214,7 +213,6 @@ namespace keepass2android.Io
|
||||
|
||||
public IDriveItemRequestBuilder getPathItem()
|
||||
{
|
||||
Kp2aLog.Log("getPathItem for " + itemLocation.ToString());
|
||||
IDriveItemRequestBuilder pathItem;
|
||||
if (!hasShare())
|
||||
{
|
||||
@@ -222,33 +220,20 @@ namespace keepass2android.Io
|
||||
}
|
||||
if ("me".Equals(itemLocation.Share.Id))
|
||||
{
|
||||
if (verbose) Kp2aLog.Log("Path share is me");
|
||||
|
||||
|
||||
if (_specialFolder == null)
|
||||
{
|
||||
if (verbose) Kp2aLog.Log("No special folder. Use drive root.");
|
||||
pathItem = client.Me.Drive.Root;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (verbose) Kp2aLog.Log("Special folder = " + _specialFolder);
|
||||
pathItem = client.Me.Drive.Special[_specialFolder];
|
||||
}
|
||||
|
||||
if (itemLocation.LocalPath.Any())
|
||||
{
|
||||
if (verbose) Kp2aLog.Log("LocalPath = " + itemLocation.LocalPathString);
|
||||
pathItem = pathItem.ItemWithPath(itemLocation.LocalPathString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (verbose) Kp2aLog.Log("Path share is not me");
|
||||
if (!itemLocation.LocalPath.Any())
|
||||
{
|
||||
String webUrl = itemLocation.Share.WebUrl;
|
||||
if (verbose) Kp2aLog.Log("Share WebUrl = " + webUrl);
|
||||
var encodedShareId = CalculateEncodedShareId(webUrl);
|
||||
return client.Shares[encodedShareId].Root;
|
||||
}
|
||||
@@ -264,7 +249,6 @@ namespace keepass2android.Io
|
||||
Android.Util.Log.Debug("KP2A", "encodedShareId = " + encodedShareId);
|
||||
pathItem = client.Shares[encodedShareId].Root;
|
||||
*/
|
||||
if (verbose) Kp2aLog.Log("Using driveId=" + itemLocation.DriveId + " and item id=" + itemLocation.LocalPath.Last().Id);
|
||||
return client.Drives[itemLocation.DriveId].Items[itemLocation.LocalPath.Last().Id];
|
||||
}
|
||||
|
||||
@@ -530,25 +514,18 @@ namespace keepass2android.Io
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
PathItemBuilder pathItemBuilder = await GetPathItemBuilder(path);
|
||||
return await
|
||||
pathItemBuilder
|
||||
.getPathItem()
|
||||
.Content
|
||||
.Request()
|
||||
.PutAsync<DriveItem>(stream);
|
||||
|
||||
PathItemBuilder pathItemBuilder = await GetPathItemBuilder(path);
|
||||
return await
|
||||
pathItemBuilder
|
||||
.getPathItem()
|
||||
.Content
|
||||
.Request()
|
||||
.PutAsync<DriveItem>(stream);
|
||||
}).Wait();
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
PathItemBuilder pathItemBuilder = await GetPathItemBuilder(path);
|
||||
pathItemBuilder.verbose = true;
|
||||
pathItemBuilder.getPathItem();
|
||||
}).Wait();
|
||||
throw convertException(e);
|
||||
}
|
||||
}
|
||||
@@ -1051,6 +1028,9 @@ namespace keepass2android.Io
|
||||
|
||||
private async Task<string> CreateFilePathAsync(string parent, string newFilename)
|
||||
{
|
||||
DriveItem driveItem = new DriveItem();
|
||||
driveItem.Name = newFilename;
|
||||
driveItem.File = new File();
|
||||
PathItemBuilder pathItemBuilder = await GetPathItemBuilder(parent);
|
||||
|
||||
//see if such a file exists already:
|
||||
@@ -1064,11 +1044,9 @@ namespace keepass2android.Io
|
||||
logDebug("building request for " + pathItemBuilder.itemLocation);
|
||||
|
||||
DriveItem res = await pathItemBuilder.getPathItem()
|
||||
|
||||
.ItemWithPath(newFilename)
|
||||
.Content
|
||||
.Children
|
||||
.Request()
|
||||
.PutAsync<DriveItem>(new MemoryStream());
|
||||
.AddAsync(driveItem);
|
||||
|
||||
return pathItemBuilder.itemLocation.BuildLocalChildLocation(res.Name, res.Id, res.ParentReference?.DriveId)
|
||||
.ToString();
|
||||
|
||||
@@ -9,14 +9,14 @@ using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
|
||||
#if !NoNet
|
||||
using Keepass2android.Javafilestorage;
|
||||
#endif
|
||||
using KeePassLib.Serialization;
|
||||
|
||||
namespace keepass2android.Io
|
||||
{
|
||||
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
|
||||
#if !NoNet
|
||||
public class WebDavFileStorage: JavaFileStorage
|
||||
{
|
||||
public WebDavFileStorage(IKp2aApp app) : base(new Keepass2android.Javafilestorage.WebDavStorage(app.CertificateErrorHandler), app)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
|
||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v9.0</TargetFrameworkVersion>
|
||||
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
@@ -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>
|
||||
@@ -31,7 +31,7 @@
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<DefineConstants>TRACE;NoNet;EXCLUDE_JAVAFILESTORAGE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
||||
@@ -53,7 +53,6 @@
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
@@ -77,23 +76,13 @@
|
||||
<Compile Include="Io\AndroidContentStorage.cs" />
|
||||
<Compile Include="Io\BuiltInFileStorage.cs" />
|
||||
<Compile Include="Io\CachingFileStorage.cs" />
|
||||
<Compile Include="Io\DropboxFileStorage.cs" />
|
||||
<Compile Include="Io\DropboxFileStorageKeys.cs" />
|
||||
<Compile Include="Io\FileDescription.cs" />
|
||||
<Compile Include="Io\FileStorageSetupActivity.cs" />
|
||||
<Compile Include="Io\FileStorageSetupInitiatorActivity.cs" />
|
||||
<Compile Include="Io\GDriveFileStorage.cs" />
|
||||
<Compile Include="Io\IFileStorage.cs" />
|
||||
<Compile Include="Io\IoUtil.cs" />
|
||||
<Compile Include="Io\JavaFileStorage.cs" />
|
||||
<Compile Include="Io\NetFtpFileStorage.cs" />
|
||||
<Compile Include="Io\OfflineSwitchableFileStorage.cs" />
|
||||
<Compile Include="Io\OneDrive2FileStorage.cs" />
|
||||
<Compile Include="Io\OneDrive2PrefixContainer.cs" />
|
||||
<Compile Include="Io\PCloudFileStorage.cs" />
|
||||
<Compile Include="Io\SftpFileStorage.cs" />
|
||||
<Compile Include="Io\OneDriveFileStorage.cs" />
|
||||
<Compile Include="Io\WebDavFileStorage.cs" />
|
||||
|
||||
<Compile Include="IProgressDialog.cs" />
|
||||
<Compile Include="PreferenceKey.cs" />
|
||||
<Compile Include="SelectStorageLocationActivityBase.cs" />
|
||||
@@ -129,14 +118,6 @@
|
||||
<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>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\KeePassLib2Android\KeePassLib2Android.csproj">
|
||||
<Project>{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}</Project>
|
||||
<Name>KeePassLib2Android</Name>
|
||||
@@ -145,10 +126,7 @@
|
||||
<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>
|
||||
@@ -161,119 +139,107 @@
|
||||
<None Include="app.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentFTP">
|
||||
<Version>31.3.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Graph">
|
||||
<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.8.2</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Arch.Core.Common">
|
||||
<Version>1.1.1.3</Version>
|
||||
<Version>1.1.1.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Arch.Core.Runtime">
|
||||
<Version>1.1.1.3</Version>
|
||||
<Version>1.1.1.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.Common">
|
||||
<Version>1.1.1.3</Version>
|
||||
<Version>1.1.1.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.LiveData">
|
||||
<Version>1.1.1.3</Version>
|
||||
<Version>1.1.1.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.LiveData.Core">
|
||||
<Version>1.1.1.3</Version>
|
||||
<Version>1.1.1.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.Runtime">
|
||||
<Version>1.1.1.3</Version>
|
||||
<Version>1.1.1.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.ViewModel">
|
||||
<Version>1.1.1.3</Version>
|
||||
<Version>1.1.1.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.Animated.Vector.Drawable">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.Annotations">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.AsyncLayoutInflater">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.Collections">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.Compat">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.CoordinaterLayout">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.Core.UI">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.Core.Utils">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.CursorAdapter">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.CustomTabs">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.CustomView">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.DocumentFile">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.DrawerLayout">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.Fragment">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.Interpolator">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.Loader">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.LocalBroadcastManager">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.Media.Compat">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.Print">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.SlidingPaneLayout">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.SwipeRefreshLayout">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.v13">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.v4">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.VersionedParcelable">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.ViewPager">
|
||||
<Version>28.0.0.3</Version>
|
||||
<Version>28.0.0.1</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
|
||||
@@ -49,11 +49,6 @@ namespace keepass2android
|
||||
get { return _activeActivity; }
|
||||
private set
|
||||
{
|
||||
if (_activeActivity != null && _activeActivity != _previouslyActiveActivity)
|
||||
{
|
||||
_previouslyActiveActivity = _activeActivity;
|
||||
|
||||
}
|
||||
_activeActivity = value;
|
||||
if (_task != null)
|
||||
_task.ActiveActivity = _activeActivity;
|
||||
@@ -65,18 +60,12 @@ namespace keepass2android
|
||||
}
|
||||
}
|
||||
|
||||
public Activity PreviouslyActiveActivity
|
||||
{
|
||||
get { return _previouslyActiveActivity; }
|
||||
|
||||
}
|
||||
|
||||
private readonly Handler _handler;
|
||||
private readonly Handler _handler;
|
||||
private readonly RunnableOnFinish _task;
|
||||
private IProgressDialog _progressDialog;
|
||||
private readonly IKp2aApp _app;
|
||||
private Thread _thread;
|
||||
private Activity _activeActivity, _previouslyActiveActivity;
|
||||
private Activity _activeActivity;
|
||||
private ProgressDialogStatusLogger _progressDialogStatusLogger;
|
||||
|
||||
public ProgressTask(IKp2aApp app, Activity activity, RunnableOnFinish task)
|
||||
|
||||
6568
src/Kp2aBusinessLogic/Resources/Resource.Designer.cs
generated
6568
src/Kp2aBusinessLogic/Resources/Resource.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@@ -72,8 +72,8 @@ namespace keepass2android
|
||||
SearchParameters sp = SearchParameters.None;
|
||||
sp.SearchInUrls = true;
|
||||
sp.SearchString = url;
|
||||
|
||||
if(sp.RegularExpression) // Validate regular expression
|
||||
|
||||
if(sp.RegularExpression) // Validate regular expression
|
||||
{
|
||||
new Regex(sp.SearchString);
|
||||
}
|
||||
@@ -104,9 +104,7 @@ namespace keepass2android
|
||||
if (String.IsNullOrWhiteSpace(host))
|
||||
return pgResults;
|
||||
foreach (PwEntry entry in database.EntriesById.Values)
|
||||
{
|
||||
if (!entry.GetSearchingEnabled())
|
||||
continue;
|
||||
{
|
||||
string otherUrl = entry.Strings.ReadSafe(PwDefs.UrlField);
|
||||
otherUrl = SprEngine.Compile(otherUrl, new SprContext(entry, database.KpDatabase, SprCompileFlags.References));
|
||||
String otherHost = ExtractHost(otherUrl);
|
||||
|
||||
@@ -88,7 +88,6 @@ namespace keepass2android
|
||||
ReadOnlyReason_ReadOnlyKitKat,
|
||||
ReadOnlyReason_LocalBackup,
|
||||
Ok,
|
||||
cancel,
|
||||
FileNotFound
|
||||
cancel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,11 +36,8 @@ namespace keepass2android
|
||||
{
|
||||
_actionToPerform = actionToPerform;
|
||||
}
|
||||
|
||||
//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()
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
if (Message == null)
|
||||
Message = "";
|
||||
@@ -49,7 +46,7 @@ namespace keepass2android
|
||||
Handler.Post(() => {_actionToPerform(Success, Message, ActiveActivity);});
|
||||
}
|
||||
else
|
||||
_actionToPerform(Success, Message, AllowInactiveActivity ? (ActiveActivity ?? PreviouslyActiveActivity) : ActiveActivity);
|
||||
_actionToPerform(Success, Message, ActiveActivity);
|
||||
base.Run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,17 +31,15 @@ namespace keepass2android
|
||||
private readonly PwEntry _entry;
|
||||
private readonly PwGroup _parentGroup;
|
||||
private readonly Activity _ctx;
|
||||
private readonly Database _db;
|
||||
|
||||
public static AddEntry GetInstance(Activity ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish) {
|
||||
|
||||
public static AddEntry GetInstance(Activity ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish, Database db) {
|
||||
|
||||
return new AddEntry(ctx, db, app, entry, parentGroup, finish);
|
||||
return new AddEntry(ctx, app, entry, parentGroup, finish);
|
||||
}
|
||||
|
||||
public AddEntry(Activity ctx, Database db, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish):base(ctx, finish) {
|
||||
public AddEntry(Activity ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish):base(ctx, finish) {
|
||||
_ctx = ctx;
|
||||
_db = db;
|
||||
_parentGroup = parentGroup;
|
||||
_parentGroup = parentGroup;
|
||||
_app = app;
|
||||
_entry = entry;
|
||||
|
||||
@@ -59,13 +57,10 @@ namespace keepass2android
|
||||
{
|
||||
_parentGroup.AddEntry(_entry, true);
|
||||
}
|
||||
|
||||
// Add entry to global
|
||||
_db.EntriesById[_entry.Uuid] = _entry;
|
||||
_db.Elements.Add(_entry);
|
||||
|
||||
// Commit to disk
|
||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
|
||||
|
||||
|
||||
// Commit to disk
|
||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
|
||||
save.SetStatusLogger(StatusLogger);
|
||||
save.Run();
|
||||
}
|
||||
@@ -91,7 +86,9 @@ namespace keepass2android
|
||||
// Mark parent group dirty
|
||||
_app.DirtyGroups.Add(parent);
|
||||
|
||||
|
||||
// Add entry to global
|
||||
_db.EntriesById[_entry.Uuid] = _entry;
|
||||
_db.Elements.Add(_entry);
|
||||
|
||||
} else
|
||||
{
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace keepass2android.database.edit
|
||||
{
|
||||
public class CopyEntry: AddEntry
|
||||
{
|
||||
public CopyEntry(Activity ctx, IKp2aApp app, PwEntry entry, OnFinish finish, Database db)
|
||||
: base(ctx, db, app, CreateCopy(entry, app), entry.ParentGroup, finish)
|
||||
public CopyEntry(Activity ctx, IKp2aApp app, PwEntry entry, OnFinish finish)
|
||||
: base(ctx, app, CreateCopy(entry, app), entry.ParentGroup, finish)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace keepass2android
|
||||
{
|
||||
if (!(e is InvalidCompositeKeyException))
|
||||
Kp2aLog.LogUnexpectedError(e);
|
||||
Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + (e.Message ?? (e is FileNotFoundException ? _app.GetResourceString(UiStringKey.FileNotFound) : "")), false, Exception);
|
||||
Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + e.Message, false, Exception);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -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, _previouslyActiveActivity;
|
||||
private Activity _activeActivity;
|
||||
|
||||
|
||||
public ProgressDialogStatusLogger StatusLogger
|
||||
@@ -53,12 +53,7 @@ namespace keepass2android
|
||||
get { return _activeActivity; }
|
||||
set
|
||||
{
|
||||
if (_activeActivity != null && _activeActivity != _previouslyActiveActivity)
|
||||
{
|
||||
_previouslyActiveActivity = _activeActivity;
|
||||
|
||||
}
|
||||
_activeActivity = value;
|
||||
_activeActivity = value;
|
||||
if (BaseOnFinish != null)
|
||||
{
|
||||
BaseOnFinish.ActiveActivity = value;
|
||||
@@ -66,15 +61,8 @@ namespace keepass2android
|
||||
}
|
||||
}
|
||||
|
||||
public Activity PreviouslyActiveActivity
|
||||
{
|
||||
get { return _previouslyActiveActivity; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected OnFinish(Activity activeActivity, Handler handler)
|
||||
protected OnFinish(Activity activeActivity, Handler handler)
|
||||
{
|
||||
ActiveActivity = activeActivity;
|
||||
BaseOnFinish = null;
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
|
||||
<AssemblyName>Kp2aKeyboardBinding</AssemblyName>
|
||||
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
|
||||
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
|
||||
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
|
||||
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>True</DebugSymbols>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
|
||||
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
|
||||
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
|
||||
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
|
||||
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -54,7 +53,7 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<LibraryProjectZip Include="..\java\Keepass2AndroidPluginSDK2\app\build\outputs\aar\app-release.aar">
|
||||
<LibraryProjectZip Include="..\java\Keepass2AndroidPluginSDK2\app\build\outputs\aar\Keepass2AndroidPluginSDK2-release.aar">
|
||||
<Link>Jars\Keepass2AndroidPluginSDK2-release.aar</Link>
|
||||
</LibraryProjectZip>
|
||||
<None Include="Jars\AboutJars.txt" />
|
||||
|
||||
Submodule src/SamsungPass updated: 56538a5be1...f3c6bbe224
@@ -1,17 +1,17 @@
|
||||
cd ..\java\JavaFileStorageTest-AS
|
||||
./gradlew assemble
|
||||
call gradlew assemble
|
||||
|
||||
cd ..\KP2ASoftkeyboard_AS
|
||||
./gradlew assemble
|
||||
call gradlew assemble
|
||||
|
||||
cd ..\Keepass2AndroidPluginSDK2
|
||||
./gradlew assemble
|
||||
call gradlew assemble
|
||||
|
||||
|
||||
cd ..\KP2AKdbLibrary
|
||||
./gradlew assemble
|
||||
call gradlew assemble
|
||||
|
||||
cd ..\PluginQR
|
||||
./gradlew assemble
|
||||
call gradlew assemble
|
||||
|
||||
cd ..\..\build-scripts
|
||||
|
||||
@@ -6,11 +6,11 @@ if exist "DropboxFileStorageKeys.cs" (
|
||||
)
|
||||
|
||||
cd ..\..\keepass2android
|
||||
call UseManifestDebug.bat
|
||||
call UseManifestNoNet.bat
|
||||
cd ..
|
||||
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86_amd64
|
||||
|
||||
msbuild KeePass.sln /target:keepass2android /p:BuildProjectReferences=true /p:Configuration="Debug" /p:Platform="Any CPU"
|
||||
msbuild KeePass.sln /target:keepass2android /p:BuildProjectReferences=true /p:Configuration="Release" /p:Platform="Any CPU"
|
||||
|
||||
cd build-scripts
|
||||
@@ -1,17 +0,0 @@
|
||||
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
|
||||
@@ -1,11 +1,11 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion '28.0.3'
|
||||
defaultConfig {
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 28
|
||||
targetSdkVersion 23
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
@@ -26,9 +26,8 @@ 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.squareup.okhttp3:okhttp:3.9.0'
|
||||
compile 'com.burgstaller:okhttp-digest:1.7'
|
||||
compile 'com.google.android.gms:play-services:4.0.30'
|
||||
compile 'com.google.http-client:google-http-client-gson:1.20.0'
|
||||
compile('com.google.api-client:google-api-client-android:1.16.0-rc') {
|
||||
|
||||
@@ -31,7 +31,147 @@ 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 {
|
||||
public class GSSContextKrb5 implements com.jcraft.jsch.GSSContext{
|
||||
|
||||
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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ 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;
|
||||
@@ -45,7 +44,6 @@ 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;
|
||||
@@ -54,7 +52,6 @@ import okhttp3.internal.tls.OkHostnameVerifier;
|
||||
public class WebDavStorage extends JavaFileStorageBase {
|
||||
|
||||
private final ICertificateErrorHandler mCertificateErrorHandler;
|
||||
private Context appContext;
|
||||
|
||||
public WebDavStorage(ICertificateErrorHandler certificateErrorHandler)
|
||||
{
|
||||
@@ -128,13 +125,9 @@ 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 = baseClient.newBuilder();
|
||||
OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||
final Map<String, CachingAuthenticator> authCache = new ConcurrentHashMap<>();
|
||||
|
||||
com.burgstaller.okhttp.digest.Credentials credentials = new com.burgstaller.okhttp.digest.Credentials(ci.username, ci.password);
|
||||
@@ -176,12 +169,6 @@ 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();
|
||||
|
||||
|
||||
@@ -460,20 +447,10 @@ public class WebDavStorage extends JavaFileStorageBase {
|
||||
if (href.endsWith("/"))
|
||||
href = href.substring(0, href.length()-1);
|
||||
int lastIndex = href.lastIndexOf("/");
|
||||
|
||||
String displayName;
|
||||
|
||||
if (lastIndex >= 0)
|
||||
displayName = href.substring(lastIndex + 1);
|
||||
return href.substring(lastIndex + 1);
|
||||
else
|
||||
displayName = href;
|
||||
|
||||
try {
|
||||
displayName = java.net.URLDecoder.decode(displayName, UTF_8);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
}
|
||||
|
||||
return displayName;
|
||||
return href;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -516,7 +493,7 @@ public class WebDavStorage extends JavaFileStorageBase {
|
||||
|
||||
@Override
|
||||
public void prepareFileUsage(Context appContext, String path) {
|
||||
this.appContext = appContext;
|
||||
//nothing to do
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2,19 +2,14 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven {
|
||||
url 'https://maven.google.com/'
|
||||
name 'Google'
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.3.2'
|
||||
classpath 'com.android.tools.build:gradle:1.2.3'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.10.3-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion '28.0.3'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.crocoapps.javafilestoragetest"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
targetSdkVersion 23
|
||||
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')
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
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>
|
||||
|
||||
@@ -9,11 +9,11 @@ buildscript {
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.3.2'
|
||||
classpath 'com.android.tools.build:gradle:3.0.1'
|
||||
|
||||
// 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'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.10.3-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
|
||||
|
||||
@@ -1,440 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -33,10 +33,8 @@ 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)
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.graphics.Paint;
|
||||
import android.graphics.Paint.Align;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region.Op;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@@ -775,9 +774,7 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
|
||||
mKeyboardChanged = false;
|
||||
}
|
||||
final Canvas canvas = mCanvas;
|
||||
canvas.save();
|
||||
canvas.clipRect(new RectF(mDirtyRect));
|
||||
|
||||
canvas.clipRect(mDirtyRect, Op.REPLACE);
|
||||
|
||||
if (mKeyboard == null) return;
|
||||
|
||||
@@ -910,8 +907,6 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
|
||||
}
|
||||
}
|
||||
|
||||
canvas.restore();
|
||||
|
||||
mDrawPending = false;
|
||||
mDirtyRect.setEmpty();
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
//
|
||||
// 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!");
|
||||
}
|
||||
@@ -1,30 +1,15 @@
|
||||
// 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: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'
|
||||
classpath 'com.android.tools.build:gradle:2.2.1'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
||||
@@ -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-5.4.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
|
||||
|
||||
@@ -8,7 +8,7 @@ buildscript {
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.3.2'
|
||||
classpath 'com.android.tools.build:gradle:3.0.1'
|
||||
}
|
||||
}
|
||||
allprojects {
|
||||
|
||||
@@ -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.10.3-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
|
||||
|
||||
5
src/java/android-filechooser-AS/.idea/gradle.xml
generated
5
src/java/android-filechooser-AS/.idea/gradle.xml
generated
@@ -3,14 +3,9 @@
|
||||
<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>
|
||||
|
||||
31
src/java/android-filechooser-AS/.idea/misc.xml
generated
31
src/java/android-filechooser-AS/.idea/misc.xml
generated
@@ -5,41 +5,36 @@
|
||||
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
||||
<option name="myNullables">
|
||||
<value>
|
||||
<list size="12">
|
||||
<list size="4">
|
||||
<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="11">
|
||||
<list size="4">
|
||||
<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="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<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">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<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>
|
||||
608
src/java/android-filechooser-AS/.idea/workspace.xml
generated
608
src/java/android-filechooser-AS/.idea/workspace.xml
generated
@@ -1,47 +1,23 @@
|
||||
<?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="">
|
||||
<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>
|
||||
<list default="true" id="a8c99766-6088-49be-bc69-6d9a3515f47d" name="Default" comment="" />
|
||||
<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="DefaultGradleProjectSettings">
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="delegatedBuild" value="true" />
|
||||
</component>
|
||||
<component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
|
||||
<component name="ExternalProjectsManager">
|
||||
<system id="GRADLE">
|
||||
<state>
|
||||
@@ -54,137 +30,162 @@
|
||||
</component>
|
||||
<component name="FileEditorManager">
|
||||
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
|
||||
<file pinned="false" current-in-tab="false">
|
||||
<file leaf-file-name="build.gradle" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/build.gradle">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="119">
|
||||
<state vertical-scroll-proportion="0.0">
|
||||
<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 pinned="false" current-in-tab="false">
|
||||
<file leaf-file-name="Kp2aFileProvider.java" 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 relative-caret-position="221">
|
||||
<caret line="36" selection-start-line="36" selection-end-line="36" />
|
||||
<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>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file pinned="false" current-in-tab="false">
|
||||
<file leaf-file-name="Kp2aFileChooserBridge.java" pinned="false" current-in-tab="true">
|
||||
<entry file="file://$PROJECT_DIR$/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileChooserBridge.java">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="357">
|
||||
<caret line="25" selection-start-line="25" selection-end-line="25" />
|
||||
<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>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<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">
|
||||
<file leaf-file-name="build.gradle" pinned="false" current-in-tab="false">
|
||||
<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 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>
|
||||
</file>
|
||||
<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">
|
||||
<file leaf-file-name="local.properties" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/local.properties">
|
||||
<provider selected="true" editor-type-id="text-editor" />
|
||||
<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>
|
||||
</file>
|
||||
<file pinned="false" current-in-tab="false">
|
||||
<file leaf-file-name="gradle.properties" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/gradle.properties">
|
||||
<provider selected="true" editor-type-id="text-editor" />
|
||||
<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>
|
||||
</file>
|
||||
<file pinned="false" current-in-tab="false">
|
||||
<file leaf-file-name="settings.gradle" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/settings.gradle">
|
||||
<provider selected="true" editor-type-id="text-editor" />
|
||||
<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>
|
||||
</file>
|
||||
</leaf>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/../../.." />
|
||||
<component name="GradleLocalSettings">
|
||||
<option name="externalProjectsViewState">
|
||||
<projects_view />
|
||||
</option>
|
||||
</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" extendedState="6">
|
||||
<component name="ProjectFrameBounds">
|
||||
<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="true" />
|
||||
<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="ProjectView">
|
||||
<navigator currentView="ProjectPane" proportions="" version="1">
|
||||
<navigator currentView="Scope" currentSubView="Project Files" proportions="" version="1">
|
||||
<flattenPackages />
|
||||
<showMembers />
|
||||
<showModules />
|
||||
<showLibraryContents />
|
||||
<hideEmptyPackages />
|
||||
<abbreviatePackageNames />
|
||||
<autoscrollToSource />
|
||||
<autoscrollFromSource />
|
||||
<sortByType />
|
||||
<manualOrder />
|
||||
<foldersAlwaysOnTop value="true" />
|
||||
</navigator>
|
||||
<panes>
|
||||
<pane id="Scope" />
|
||||
<pane id="PackagesPane" />
|
||||
<pane id="AndroidView" />
|
||||
<pane id="ProjectPane">
|
||||
<pane id="ProjectPane" />
|
||||
<pane id="AndroidView">
|
||||
<subPane>
|
||||
<expand>
|
||||
<path>
|
||||
<item name="android-filechooser-AS" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="android-filechooser-AS" type="8a07ba80:GradleTreeStructureProvider$GradleModuleDirectoryNode" />
|
||||
</path>
|
||||
</expand>
|
||||
<select />
|
||||
<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="PackagesPane" />
|
||||
</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">
|
||||
@@ -200,7 +201,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="Auto" />
|
||||
<option name="DEBUGGER_TYPE" value="Java" />
|
||||
<option name="USE_LAST_SELECTED_DEVICE" value="false" />
|
||||
<option name="PREFERRED_AVD" value="" />
|
||||
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="-1" />
|
||||
@@ -235,7 +236,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="Auto" />
|
||||
<option name="DEBUGGER_TYPE" value="Java" />
|
||||
<option name="USE_LAST_SELECTED_DEVICE" value="false" />
|
||||
<option name="PREFERRED_AVD" value="" />
|
||||
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="-1" />
|
||||
@@ -254,6 +255,42 @@
|
||||
</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="" />
|
||||
@@ -275,25 +312,61 @@
|
||||
<patterns />
|
||||
<method />
|
||||
</configuration>
|
||||
<configuration default="true" type="JUnit" factoryName="JUnit">
|
||||
<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">
|
||||
<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="TEST_OBJECT" value="class" />
|
||||
<option name="GROUP_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="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 />
|
||||
<patterns />
|
||||
<properties />
|
||||
<listeners />
|
||||
<method />
|
||||
</configuration>
|
||||
<configuration default="true" type="TestNGTestDiscovery" factoryName="TestNG Test Discovery" changeList="All">
|
||||
@@ -324,38 +397,20 @@
|
||||
<listeners />
|
||||
<method />
|
||||
</configuration>
|
||||
<configuration name="<template>" 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="<template>" 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>
|
||||
@@ -364,49 +419,41 @@
|
||||
<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="1936" height="1056" extended-state="6" />
|
||||
<editor active="true" />
|
||||
<frame x="-8" y="-8" width="1382" height="744" extended-state="7" />
|
||||
<editor active="false" />
|
||||
<layout>
|
||||
<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	" 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" />
|
||||
<window_info id="Palette	" 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" />
|
||||
</layout>
|
||||
</component>
|
||||
<component name="Vcs.Log.UiProperties">
|
||||
@@ -417,56 +464,201 @@
|
||||
<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 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" />
|
||||
</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 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 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 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 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 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">
|
||||
<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>
|
||||
</provider>
|
||||
</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>
|
||||
</provider>
|
||||
</entry>
|
||||
|
||||
@@ -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" 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" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="java-gradle" name="Java-Gradle">
|
||||
<configuration>
|
||||
@@ -7,13 +7,23 @@
|
||||
<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" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="jdk" jdkName="1.7" jdkType="JavaSDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -1,123 +1,92 @@
|
||||
<?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" 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" external.system.module.group="android-filechooser-AS" external.system.module.version="unspecified" 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" />
|
||||
<afterSyncTasks>
|
||||
<task>generateDebugSources</task>
|
||||
</afterSyncTasks>
|
||||
<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" />
|
||||
<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;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="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
||||
<option name="PROJECT_TYPE" value="1" />
|
||||
<option name="LIBRARY_PROJECT" value="true" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<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" />
|
||||
<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" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<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/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/buildConfig/debug" isTestSource="false" 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/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/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<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$/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$/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" />
|
||||
<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" />
|
||||
<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" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 28 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<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" />
|
||||
<orderEntry type="library" exported="" name="support-v4-18.0.0" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -1,12 +1,12 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion '28.0.3'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 28
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 15
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@@ -23,5 +23,5 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:support-v4:28.0.0'
|
||||
compile 'com.android.support:support-v4:26.1.0'
|
||||
}
|
||||
|
||||
@@ -9,5 +9,8 @@
|
||||
<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>
|
||||
@@ -1,30 +1,20 @@
|
||||
// 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: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.android.tools.build:gradle:2.1.3'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
dependencies {
|
||||
}
|
||||
android {
|
||||
buildToolsVersion '23.0.2'
|
||||
}
|
||||
@@ -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.10.3-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
|
||||
|
||||
BIN
src/java/kp2akeytransform/bin/kp2akeytransform.jar
Normal file
BIN
src/java/kp2akeytransform/bin/kp2akeytransform.jar
Normal file
Binary file not shown.
@@ -1,469 +0,0 @@
|
||||
using System;
|
||||
using Android.Content;
|
||||
using Javax.Crypto;
|
||||
using Java.Security;
|
||||
using Java.Lang;
|
||||
using Android.Views.InputMethods;
|
||||
using Android.App;
|
||||
using Android.OS;
|
||||
using Android.Security.Keystore;
|
||||
using Android.Preferences;
|
||||
using Android.Util;
|
||||
using Android.Widget;
|
||||
using AndroidX.Biometric;
|
||||
using AndroidX.Fragment.App;
|
||||
using Java.IO;
|
||||
using Java.Security.Cert;
|
||||
using Java.Util.Concurrent;
|
||||
using Javax.Crypto.Spec;
|
||||
using Exception = System.Exception;
|
||||
using File = System.IO.File;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public interface IBiometricAuthCallback
|
||||
{
|
||||
void OnBiometricAuthSucceeded();
|
||||
void OnBiometricError(string toString);
|
||||
void OnBiometricAttemptFailed(string message);
|
||||
}
|
||||
|
||||
public class BiometricModule
|
||||
{
|
||||
public AndroidX.Fragment.App.FragmentActivity Activity { get; set; }
|
||||
|
||||
public BiometricModule(AndroidX.Fragment.App.FragmentActivity activity)
|
||||
{
|
||||
Activity = activity;
|
||||
}
|
||||
|
||||
|
||||
public KeyguardManager KeyguardManager
|
||||
{
|
||||
get
|
||||
{
|
||||
return (KeyguardManager)Activity.GetSystemService("keyguard");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public KeyStore Keystore
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return KeyStore.GetInstance("AndroidKeyStore");
|
||||
}
|
||||
catch (KeyStoreException e)
|
||||
{
|
||||
throw new RuntimeException("Failed to get an instance of KeyStore", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public KeyGenerator KeyGenerator
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, "AndroidKeyStore");
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
|
||||
}
|
||||
catch (NoSuchProviderException e)
|
||||
{
|
||||
throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Cipher Cipher
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return Cipher.GetInstance(KeyProperties.KeyAlgorithmAes + "/"
|
||||
+ KeyProperties.BlockModeCbc + "/"
|
||||
+ KeyProperties.EncryptionPaddingPkcs7);
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new RuntimeException("Failed to get an instance of Cipher", e);
|
||||
}
|
||||
catch (NoSuchPaddingException e)
|
||||
{
|
||||
throw new RuntimeException("Failed to get an instance of Cipher", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ISharedPreferences SharedPreferences
|
||||
{
|
||||
get { return PreferenceManager.GetDefaultSharedPreferences(Activity); }
|
||||
}
|
||||
|
||||
public bool IsAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
return BiometricManager.From(Activity).CanAuthenticate() ==
|
||||
BiometricManager.BiometricSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsHardwareAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = BiometricManager.From(Activity).CanAuthenticate();
|
||||
Kp2aLog.Log("BiometricHardware available = " + result);
|
||||
return result == BiometricManager.BiometricSuccess
|
||||
|| result == BiometricManager.BiometricErrorNoneEnrolled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class BiometricCrypt : IBiometricIdentifier
|
||||
{
|
||||
protected const string FailedToInitCipher = "Failed to init Cipher";
|
||||
|
||||
protected readonly string _keyId;
|
||||
|
||||
protected Cipher _cipher;
|
||||
private CancellationSignal _cancellationSignal;
|
||||
protected BiometricPrompt.CryptoObject _cryptoObject;
|
||||
|
||||
protected KeyStore _keystore;
|
||||
|
||||
private BiometricPrompt _biometricPrompt;
|
||||
private FragmentActivity _activity;
|
||||
private BiometricAuthCallbackAdapter _biometricAuthCallbackAdapter;
|
||||
|
||||
public BiometricCrypt(BiometricModule biometric, string keyId)
|
||||
{
|
||||
Kp2aLog.Log("FP: Create " + this.GetType().Name);
|
||||
_keyId = keyId;
|
||||
_cipher = biometric.Cipher;
|
||||
_keystore = biometric.Keystore;
|
||||
_activity = biometric.Activity;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public abstract bool Init();
|
||||
|
||||
|
||||
protected static string GetAlias(string keyId)
|
||||
{
|
||||
return "keepass2android." + keyId;
|
||||
}
|
||||
protected static string GetIvPrefKey(string prefKey)
|
||||
{
|
||||
return prefKey + "_iv";
|
||||
}
|
||||
|
||||
public void StartListening(IBiometricAuthCallback callback)
|
||||
{
|
||||
_biometricAuthCallbackAdapter = new BiometricAuthCallbackAdapter(callback, _activity);
|
||||
StartListening(_biometricAuthCallbackAdapter);
|
||||
}
|
||||
|
||||
public void StopListening()
|
||||
{
|
||||
_biometricAuthCallbackAdapter?.IgnoreNextError();
|
||||
_biometricPrompt?.CancelAuthentication();
|
||||
}
|
||||
|
||||
public bool HasUserInterface
|
||||
{
|
||||
get { return true; }
|
||||
|
||||
}
|
||||
|
||||
public void StartListening(BiometricPrompt.AuthenticationCallback callback)
|
||||
{
|
||||
|
||||
Kp2aLog.Log("Fingerprint: StartListening ");
|
||||
|
||||
var executor = Executors.NewSingleThreadExecutor();
|
||||
_biometricPrompt = new BiometricPrompt(_activity, executor, callback);
|
||||
|
||||
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
|
||||
.SetTitle(_activity.GetString(AppNames.AppNameResource))
|
||||
.SetSubtitle(_activity.GetString(Resource.String.unlock_database_title))
|
||||
.SetNegativeButtonText(_activity.GetString(Android.Resource.String.Cancel))
|
||||
.SetConfirmationRequired(false)
|
||||
.Build();
|
||||
|
||||
|
||||
_biometricPrompt.Authenticate(promptInfo, _cryptoObject);
|
||||
|
||||
}
|
||||
|
||||
public string Encrypt(string textToEncrypt)
|
||||
{
|
||||
Kp2aLog.Log("FP: Encrypting");
|
||||
return Base64.EncodeToString(_cipher.DoFinal(System.Text.Encoding.UTF8.GetBytes(textToEncrypt)), 0);
|
||||
}
|
||||
|
||||
|
||||
public void StoreEncrypted(string textToEncrypt, string prefKey, Context context)
|
||||
{
|
||||
var edit = PreferenceManager.GetDefaultSharedPreferences(context).Edit();
|
||||
StoreEncrypted(textToEncrypt, prefKey, edit);
|
||||
edit.Commit();
|
||||
}
|
||||
|
||||
public void StoreEncrypted(string textToEncrypt, string prefKey, ISharedPreferencesEditor edit)
|
||||
{
|
||||
edit.PutString(prefKey, Encrypt(textToEncrypt));
|
||||
edit.PutString(GetIvPrefKey(prefKey), Base64.EncodeToString(CipherIv, 0));
|
||||
|
||||
}
|
||||
|
||||
|
||||
private byte[] CipherIv
|
||||
{
|
||||
get { return _cipher.GetIV(); }
|
||||
}
|
||||
}
|
||||
|
||||
public interface IBiometricIdentifier
|
||||
{
|
||||
bool Init();
|
||||
void StartListening(IBiometricAuthCallback callback);
|
||||
|
||||
void StopListening();
|
||||
bool HasUserInterface { get; }
|
||||
}
|
||||
|
||||
public class BiometricDecryption : BiometricCrypt
|
||||
{
|
||||
private readonly Context _context;
|
||||
private readonly byte[] _iv;
|
||||
|
||||
|
||||
public BiometricDecryption(BiometricModule biometric, string keyId, byte[] iv) : base(biometric, keyId)
|
||||
{
|
||||
_iv = iv;
|
||||
}
|
||||
|
||||
public BiometricDecryption(BiometricModule biometric, string keyId, Context context, string prefKey)
|
||||
: base(biometric, keyId)
|
||||
{
|
||||
_context = context;
|
||||
_iv = Base64.Decode(PreferenceManager.GetDefaultSharedPreferences(context).GetString(GetIvPrefKey(prefKey), null), 0);
|
||||
}
|
||||
|
||||
public static bool IsSetUp(Context context, string prefKey)
|
||||
{
|
||||
return PreferenceManager.GetDefaultSharedPreferences(context).GetString(GetIvPrefKey(prefKey), null) != null;
|
||||
}
|
||||
|
||||
public override bool Init()
|
||||
{
|
||||
Kp2aLog.Log("FP: Init for Dec");
|
||||
try
|
||||
{
|
||||
_keystore.Load(null);
|
||||
var key = _keystore.GetKey(GetAlias(_keyId), null);
|
||||
var ivParams = new IvParameterSpec(_iv);
|
||||
_cipher.Init(CipherMode.DecryptMode, key, ivParams);
|
||||
|
||||
_cryptoObject = new BiometricPrompt.CryptoObject(_cipher);
|
||||
return true;
|
||||
}
|
||||
catch (KeyPermanentlyInvalidatedException e)
|
||||
{
|
||||
Kp2aLog.Log("FP: KeyPermanentlyInvalidatedException." + e.ToString());
|
||||
return false;
|
||||
}
|
||||
catch (KeyStoreException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (CertificateException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (UnrecoverableKeyException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (InvalidKeyException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string Decrypt(string encryted)
|
||||
{
|
||||
Kp2aLog.Log("FP: Decrypting ");
|
||||
byte[] encryptedBytes = Base64.Decode(encryted, 0);
|
||||
return System.Text.Encoding.UTF8.GetString(_cipher.DoFinal(encryptedBytes));
|
||||
}
|
||||
|
||||
public string DecryptStored(string prefKey)
|
||||
{
|
||||
string enc = PreferenceManager.GetDefaultSharedPreferences(_context).GetString(prefKey, null);
|
||||
return Decrypt(enc);
|
||||
}
|
||||
}
|
||||
|
||||
public class BiometricEncryption : BiometricCrypt
|
||||
{
|
||||
|
||||
private KeyGenerator _keyGen;
|
||||
|
||||
|
||||
public BiometricEncryption(BiometricModule biometric, string keyId) :
|
||||
base(biometric, keyId)
|
||||
{
|
||||
_keyGen = biometric.KeyGenerator;
|
||||
Kp2aLog.Log("FP: CreateKey ");
|
||||
CreateKey();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a symmetric key in the Android Key Store which can only be used after the user
|
||||
/// has authenticated with biometry.
|
||||
/// </summary>
|
||||
private void CreateKey()
|
||||
{
|
||||
try
|
||||
{
|
||||
_keystore.Load(null);
|
||||
_keyGen.Init(new KeyGenParameterSpec.Builder(GetAlias(_keyId),
|
||||
KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
|
||||
.SetBlockModes(KeyProperties.BlockModeCbc)
|
||||
// Require the user to authenticate with biometry to authorize every use
|
||||
// of the key
|
||||
.SetEncryptionPaddings(KeyProperties.EncryptionPaddingPkcs7)
|
||||
.SetUserAuthenticationRequired(true)
|
||||
|
||||
.Build());
|
||||
_keyGen.GenerateKey();
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
catch (InvalidAlgorithmParameterException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
catch (CertificateException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Kp2aLog.LogUnexpectedError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Init()
|
||||
{
|
||||
Kp2aLog.Log("FP: Init for Enc ");
|
||||
try
|
||||
{
|
||||
_keystore.Load(null);
|
||||
var key = _keystore.GetKey(GetAlias(_keyId), null);
|
||||
_cipher.Init(CipherMode.EncryptMode, key);
|
||||
|
||||
_cryptoObject = new BiometricPrompt.CryptoObject(_cipher);
|
||||
return true;
|
||||
}
|
||||
catch (KeyPermanentlyInvalidatedException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (KeyStoreException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (CertificateException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (UnrecoverableKeyException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (InvalidKeyException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class BiometricAuthCallbackAdapter : BiometricPrompt.AuthenticationCallback
|
||||
{
|
||||
private readonly IBiometricAuthCallback _callback;
|
||||
private readonly Context _context;
|
||||
private bool _ignoreNextError;
|
||||
|
||||
public BiometricAuthCallbackAdapter(IBiometricAuthCallback callback, Context context)
|
||||
{
|
||||
_callback = callback;
|
||||
_context = context;
|
||||
}
|
||||
|
||||
|
||||
public override void OnAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result)
|
||||
{
|
||||
new Handler(Looper.MainLooper).Post(() => _callback.OnBiometricAuthSucceeded());
|
||||
}
|
||||
|
||||
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.OnBiometricAttemptFailed(_context.Resources.GetString(Resource.String.fingerprint_not_recognized)));
|
||||
}
|
||||
|
||||
public void IgnoreNextError()
|
||||
{
|
||||
_ignoreNextError = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,7 +27,6 @@ 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-r0"),
|
||||
ctx.GetString(Resource.String.ChangeLog_1_07b),
|
||||
ctx.GetString(Resource.String.ChangeLog_1_07),
|
||||
ctx.GetString(Resource.String.ChangeLog_1_06),
|
||||
@@ -112,18 +111,7 @@ namespace keepass2android
|
||||
|
||||
}
|
||||
|
||||
private static string BuildChangelogString(Context ctx, int changeLogResId, string version)
|
||||
{
|
||||
string result = "Version " + version + "\n";
|
||||
foreach (var item in ctx.Resources.GetStringArray(changeLogResId))
|
||||
{
|
||||
result += " * " + item + "\n";
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
private const string HtmlStart = @"<html>
|
||||
private const string HtmlStart = @"<html>
|
||||
<head>
|
||||
<style type='text/css'>
|
||||
a { color:#000000 }
|
||||
@@ -159,36 +147,36 @@ namespace keepass2android
|
||||
{
|
||||
string versionLog2 = versionLog;
|
||||
bool title = true;
|
||||
if (isFirst)
|
||||
{
|
||||
if (isFirst)
|
||||
{
|
||||
|
||||
bool showDonateOption = true;
|
||||
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(ctx);
|
||||
if (prefs.GetBoolean(ctx.GetString(Resource.String.NoDonationReminder_key), false))
|
||||
showDonateOption = false;
|
||||
|
||||
bool showDonateOption = true;
|
||||
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(ctx);
|
||||
if (prefs.GetBoolean(ctx.GetString(Resource.String.NoDonationReminder_key), false))
|
||||
showDonateOption = false;
|
||||
long usageCount = prefs.GetLong(ctx.GetString(Resource.String.UsageCount_key), 0);
|
||||
|
||||
long usageCount = prefs.GetLong(ctx.GetString(Resource.String.UsageCount_key), 0);
|
||||
if (usageCount <= 5)
|
||||
showDonateOption = false;
|
||||
|
||||
if (usageCount <= 5)
|
||||
showDonateOption = false;
|
||||
if (showDonateOption)
|
||||
{
|
||||
if (versionLog2.EndsWith("\n") == false)
|
||||
versionLog2 += "\n";
|
||||
string donateUrl = ctx.GetString(Resource.String.donate_url,
|
||||
new Java.Lang.Object[]{ctx.Resources.Configuration.Locale.Language,
|
||||
ctx.PackageName
|
||||
});
|
||||
|
||||
if (showDonateOption)
|
||||
{
|
||||
if (versionLog2.EndsWith("\n") == false)
|
||||
versionLog2 += "\n";
|
||||
string donateUrl = ctx.GetString(Resource.String.donate_url,
|
||||
new Java.Lang.Object[]{ctx.Resources.Configuration.Locale.Language,
|
||||
ctx.PackageName
|
||||
});
|
||||
|
||||
versionLog2 += " * <a href=\"" + donateUrl
|
||||
+ "\">" +
|
||||
ctx.GetString(Resource.String.ChangeLog_keptDonate)
|
||||
+ "<a/>";
|
||||
}
|
||||
isFirst = false;
|
||||
}
|
||||
foreach (string line in versionLog2.Split('\n'))
|
||||
versionLog2 += " * <a href=\"" + donateUrl
|
||||
+ "\">" +
|
||||
ctx.GetString(Resource.String.ChangeLog_keptDonate)
|
||||
+ "<a/>";
|
||||
}
|
||||
isFirst = false;
|
||||
}
|
||||
foreach (string line in versionLog2.Split('\n'))
|
||||
{
|
||||
string w = line.Trim();
|
||||
if (title)
|
||||
|
||||
@@ -15,7 +15,7 @@ using Android.Widget;
|
||||
namespace keepass2android
|
||||
{
|
||||
[Activity(Label = AppNames.AppName, Theme = "@style/MyTheme_ActionBar", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden)]
|
||||
public class CloseImmediatelyActivity : AndroidX.AppCompat.App.AppCompatActivity
|
||||
public class CloseImmediatelyActivity : AppCompatActivity
|
||||
{
|
||||
protected override void OnResume()
|
||||
{
|
||||
|
||||
@@ -227,7 +227,7 @@ namespace keepass2android
|
||||
newEntry.SetUuid(new PwUuid(true), true); // Create new UUID
|
||||
string strTitle = newEntry.Strings.ReadSafe(PwDefs.TitleField);
|
||||
newEntry.Strings.Set(PwDefs.TitleField, new ProtectedString(false, strTitle + " (" + Android.OS.Build.Model + ")"));
|
||||
var addTask = new AddEntry(this, App.Kp2a.CurrentDb, App.Kp2a, newEntry,item.Entry.ParentGroup,new ActionOnFinish(this, (success, message, activity) => ((ConfigureChildDatabasesActivity)activity).Update()));
|
||||
var addTask = new AddEntry(this, App.Kp2a, newEntry,item.Entry.ParentGroup,new ActionOnFinish(this, (success, message, activity) => ((ConfigureChildDatabasesActivity)activity).Update()));
|
||||
|
||||
ProgressTask pt = new ProgressTask(App.Kp2a, this, addTask);
|
||||
pt.Run();
|
||||
@@ -284,7 +284,7 @@ namespace keepass2android
|
||||
var listView = FindViewById<ListView>(Android.Resource.Id.List);
|
||||
listView.Adapter = _adapter;
|
||||
|
||||
SetSupportActionBar(FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.mytoolbar));
|
||||
SetSupportActionBar(FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar));
|
||||
|
||||
FindViewById<Button>(Resource.Id.add_child_db_button).Click += (sender, args) =>
|
||||
{
|
||||
@@ -366,7 +366,7 @@ namespace keepass2android
|
||||
{KeeAutoExecExt.ThisDeviceId, true}
|
||||
})));
|
||||
|
||||
var addTask = new AddEntry(this, db, App.Kp2a, newEntry, autoOpenGroup, new ActionOnFinish(this, (success, message, activity) => (activity as ConfigureChildDatabasesActivity)?.Update()));
|
||||
var addTask = new AddEntry(this, App.Kp2a, newEntry, autoOpenGroup, new ActionOnFinish(this, (success, message, activity) => (activity as ConfigureChildDatabasesActivity)?.Update()));
|
||||
|
||||
ProgressTask pt = new ProgressTask(App.Kp2a, this, addTask);
|
||||
pt.Run();
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace keepass2android
|
||||
[Activity(Label = "@string/app_name",
|
||||
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
|
||||
Theme = "@style/MyTheme_ActionBar")]
|
||||
public class CreateDatabaseActivity : AndroidX.AppCompat.App.AppCompatActivity
|
||||
public class CreateDatabaseActivity : AppCompatActivity
|
||||
{
|
||||
private IOConnectionInfo _ioc;
|
||||
private string _keyfileFilename;
|
||||
@@ -141,9 +141,8 @@ namespace keepass2android
|
||||
Android.Graphics.Color color = new Android.Graphics.Color (224, 224, 224);
|
||||
btnTogglePassword.SetColorFilter (color, mMode);
|
||||
|
||||
Util.SetNoPersonalizedLearning(FindViewById(Resource.Id.root));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
readonly PasswordFont _passwordFont = new PasswordFont();
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace keepass2android
|
||||
{
|
||||
public const String KeyEntry = "entry";
|
||||
public const String KeyRefreshPos = "refresh_pos";
|
||||
public const String KeyActivateKeyboard = "activate_keyboard";
|
||||
public const String KeyCloseAfterCreate = "close_after_create";
|
||||
public const String KeyGroupFullPath = "groupfullpath_key";
|
||||
|
||||
public const int requestCodeBinaryFilename = 42376;
|
||||
@@ -480,13 +480,13 @@ namespace keepass2android
|
||||
|
||||
|
||||
|
||||
internal void StartNotificationsService(bool activateKeyboard)
|
||||
internal void StartNotificationsService(bool closeAfterCreate)
|
||||
{
|
||||
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(KeyActivateKeyboard, activateKeyboard);
|
||||
showNotIntent.PutExtra(KeyCloseAfterCreate, closeAfterCreate);
|
||||
|
||||
StartService(showNotIntent);
|
||||
}
|
||||
@@ -829,7 +829,7 @@ namespace keepass2android
|
||||
PopulateStandardText(Resource.Id.entry_comment, Resource.Id.entryfield_container_comment, PwDefs.NotesField);
|
||||
RegisterTextPopup(FindViewById<RelativeLayout>(Resource.Id.comment_container),
|
||||
FindViewById(Resource.Id.comment_vdots), PwDefs.NotesField);
|
||||
|
||||
|
||||
PopulateText(Resource.Id.entry_tags, Resource.Id.entryfield_container_tags, concatTags(Entry.Tags));
|
||||
PopulateText(Resource.Id.entry_override_url, Resource.Id.entryfield_container_overrideurl, Entry.OverrideUrl);
|
||||
|
||||
|
||||
@@ -63,9 +63,7 @@ namespace keepass2android
|
||||
|
||||
const string IntentContinueWithEditing = "ContinueWithEditing";
|
||||
|
||||
private PasswordFont _passwordFont = new PasswordFont();
|
||||
|
||||
EntryEditActivityState State
|
||||
EntryEditActivityState State
|
||||
{
|
||||
get { return App.Kp2a.EntryEditActivityState; }
|
||||
}
|
||||
@@ -113,8 +111,6 @@ namespace keepass2android
|
||||
SetContentView(Resource.Layout.entry_edit);
|
||||
_closeForReload = false;
|
||||
|
||||
Util.SetNoPersonalizedLearning(FindViewById(Resource.Id.entry_scroll));
|
||||
|
||||
// Likely the app has been killed exit the activity
|
||||
if (!App.Kp2a.DatabaseIsUnlocked)
|
||||
{
|
||||
@@ -295,10 +291,8 @@ namespace keepass2android
|
||||
State.EntryModified = true;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
@@ -403,7 +397,6 @@ namespace keepass2android
|
||||
if (State.ShowPassword)
|
||||
{
|
||||
password.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
|
||||
_passwordFont.ApplyTo(password);
|
||||
confpassword.Visibility = ViewStates.Gone;
|
||||
}
|
||||
else
|
||||
@@ -497,7 +490,7 @@ namespace keepass2android
|
||||
ActionOnFinish closeOrShowError = new ActionOnFinish(this, (success, message, activity) => {
|
||||
if (success)
|
||||
{
|
||||
activity?.Finish();
|
||||
activity.Finish();
|
||||
} else
|
||||
{
|
||||
OnFinish.DisplayMessage(activity, message, true);
|
||||
@@ -505,9 +498,6 @@ 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) =>
|
||||
{
|
||||
@@ -516,7 +506,7 @@ namespace keepass2android
|
||||
},closeOrShowError);
|
||||
|
||||
if ( State.IsNew ) {
|
||||
runnable = AddEntry.GetInstance(this, App.Kp2a, newEntry, State.ParentGroup, afterAddEntry, db);
|
||||
runnable = AddEntry.GetInstance(this, App.Kp2a, newEntry, State.ParentGroup, afterAddEntry);
|
||||
} else {
|
||||
runnable = new UpdateEntry(this, App.Kp2a, initialEntry, newEntry, closeOrShowError);
|
||||
}
|
||||
@@ -575,9 +565,7 @@ 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));
|
||||
@@ -927,15 +915,7 @@ namespace keepass2android
|
||||
item.SetVisible(false);
|
||||
foreach (View v in _editModeHiddenViews)
|
||||
v.Visibility = ViewStates.Visible;
|
||||
State.EditMode.ShowAddAttachments = true;
|
||||
State.EditMode.ShowAddExtras = true;
|
||||
ViewGroup binariesGroup = (ViewGroup)FindViewById(Resource.Id.binaries);
|
||||
binariesGroup.Visibility = ViewStates.Visible;
|
||||
FindViewById(Resource.Id.entry_binaries_container).Visibility = ViewStates.Visible;
|
||||
((Button)FindViewById(Resource.Id.add_advanced)).Visibility = ViewStates.Visible;
|
||||
FindViewById(Resource.Id.entry_extras_container).Visibility = ViewStates.Visible;
|
||||
|
||||
return true;
|
||||
return true;
|
||||
case Android.Resource.Id.Home:
|
||||
OnBackPressed();
|
||||
return true;
|
||||
@@ -1051,8 +1031,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;
|
||||
_passwordFont.ApplyTo(((TextView)ees.FindViewById(Resource.Id.value)));
|
||||
((CheckBox)ees.FindViewById(Resource.Id.protection)).Checked = pair.Value.IsProtected;
|
||||
|
||||
((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));
|
||||
@@ -1113,9 +1093,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;
|
||||
dlgView.FindViewById<CheckBox>(Resource.Id.protection).Checked = ees.FindViewById<CheckBox>(Resource.Id.protection).Checked;
|
||||
|
||||
var titleView = ((AutoCompleteTextView)dlgView.FindViewById(Resource.Id.title));
|
||||
titleView.Adapter = new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, Android.Resource.Id.Text1, AdditionalKeys);
|
||||
@@ -1160,10 +1138,6 @@ 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));
|
||||
|
||||
|
||||
@@ -18,31 +18,17 @@ namespace keepass2android
|
||||
return keys;
|
||||
}
|
||||
|
||||
protected bool? manualShowAddAttachments = null;
|
||||
public virtual bool ShowAddAttachments
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public virtual bool ShowAddAttachments
|
||||
{
|
||||
get
|
||||
{
|
||||
if (manualShowAddAttachments != null) return (bool)manualShowAddAttachments;
|
||||
return true; }
|
||||
set { manualShowAddAttachments = value; }
|
||||
}
|
||||
public virtual bool ShowAddExtras
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
|
||||
protected bool? manualShowAddExtras = null;
|
||||
|
||||
public virtual bool ShowAddExtras
|
||||
{
|
||||
get
|
||||
{
|
||||
if (manualShowAddExtras != null) return (bool) manualShowAddExtras;
|
||||
return true;
|
||||
}
|
||||
set { manualShowAddExtras = value; }
|
||||
}
|
||||
|
||||
public virtual string GetTitle(string key)
|
||||
public virtual string GetTitle(string key)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
#if !NoNet
|
||||
using FluentFTP;
|
||||
using System.Net.FtpClient;
|
||||
using Keepass2android.Javafilestorage;
|
||||
|
||||
#endif
|
||||
using System.Text;
|
||||
|
||||
@@ -13,12 +14,8 @@ using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
|
||||
using Java.IO;
|
||||
using keepass2android.Io;
|
||||
#if !EXCLUDE_JAVAFILESTORAGE
|
||||
using Keepass2android.Javafilestorage;
|
||||
#endif
|
||||
using KeePassLib.Serialization;
|
||||
using KeePassLib.Utility;
|
||||
|
||||
@@ -188,7 +185,7 @@ namespace keepass2android
|
||||
string pathAndQuery = uri.PathAndQuery;
|
||||
|
||||
var host = uri.Host;
|
||||
var localPath = WebUtility.UrlDecode(pathAndQuery);
|
||||
var localPath = pathAndQuery;
|
||||
|
||||
|
||||
if (!uri.IsDefaultPort)
|
||||
@@ -459,7 +456,7 @@ namespace keepass2android
|
||||
_activity.StartActivityForResult(i, _requestCode);
|
||||
|
||||
#else
|
||||
Toast.MakeText(Application.Context, "File chooser is excluded!", ToastLength.Long).Show();
|
||||
Toast.MakeText(this, "File chooser is excluded!", ToastLength.Long).Show();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ using Object = Java.Lang.Object;
|
||||
namespace keepass2android
|
||||
{
|
||||
[Activity(Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden, Theme = "@style/MyTheme_Blue")]
|
||||
public class FileStorageSelectionActivity : AndroidX.AppCompat.App.AppCompatActivity
|
||||
public class FileStorageSelectionActivity : AppCompatActivity
|
||||
{
|
||||
private readonly ActivityDesign _design;
|
||||
|
||||
@@ -84,7 +84,8 @@ namespace keepass2android
|
||||
if (context.Intent.GetBooleanExtra(AllowThirdPartyAppSend, false))
|
||||
_displayedProtocolIds.Add("androidsend");
|
||||
#if NoNet
|
||||
_displayedProtocolIds.Add("kp2a");
|
||||
//don't display "get regular version", is classified as deceptive ad by Google. Haha.
|
||||
//_displayedProtocolIds.Add("kp2a");
|
||||
#endif
|
||||
_displayedProtocolIds = _displayedProtocolIds.GroupBy(p => App.Kp2a.GetStorageMainTypeDisplayName(p))
|
||||
.Select(g => string.Join(",", g)).ToList();
|
||||
@@ -238,7 +239,7 @@ namespace keepass2android
|
||||
|
||||
SetContentView(Resource.Layout.filestorage_selection);
|
||||
|
||||
var toolbar = FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.mytoolbar);
|
||||
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar);
|
||||
|
||||
SetSupportActionBar(toolbar);
|
||||
|
||||
|
||||
472
src/keepass2android/FingerprintModule.cs
Normal file
472
src/keepass2android/FingerprintModule.cs
Normal file
@@ -0,0 +1,472 @@
|
||||
using System;
|
||||
using Android.Content;
|
||||
using Javax.Crypto;
|
||||
using Java.Security;
|
||||
using Java.Lang;
|
||||
using Android.Views.InputMethods;
|
||||
using Android.App;
|
||||
using Android.Hardware.Fingerprints;
|
||||
using Android.OS;
|
||||
using Android.Security.Keystore;
|
||||
using Android.Preferences;
|
||||
using Android.Util;
|
||||
using Android.Widget;
|
||||
using Java.IO;
|
||||
using Java.Security.Cert;
|
||||
using Javax.Crypto.Spec;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
public interface IFingerprintAuthCallback
|
||||
{
|
||||
void OnFingerprintAuthSucceeded();
|
||||
void OnFingerprintError(string toString);
|
||||
}
|
||||
|
||||
public class FingerprintModule
|
||||
{
|
||||
public Context Context { get; set; }
|
||||
|
||||
public FingerprintModule (Context context)
|
||||
{
|
||||
Context = context;
|
||||
}
|
||||
|
||||
public FingerprintManager FingerprintManager
|
||||
{
|
||||
get { return Context.GetSystemService(Context.FingerprintService) as FingerprintManager; }
|
||||
}
|
||||
|
||||
public KeyguardManager KeyguardManager
|
||||
{
|
||||
get
|
||||
{
|
||||
return (KeyguardManager) Context.GetSystemService("keyguard");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public KeyStore Keystore
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return KeyStore.GetInstance("AndroidKeyStore");
|
||||
}
|
||||
catch (KeyStoreException e)
|
||||
{
|
||||
throw new RuntimeException("Failed to get an instance of KeyStore", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public KeyGenerator KeyGenerator
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, "AndroidKeyStore");
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
|
||||
}
|
||||
catch (NoSuchProviderException e)
|
||||
{
|
||||
throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Cipher Cipher
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return Cipher.GetInstance(KeyProperties.KeyAlgorithmAes + "/"
|
||||
+ KeyProperties.BlockModeCbc + "/"
|
||||
+ KeyProperties.EncryptionPaddingPkcs7);
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new RuntimeException("Failed to get an instance of Cipher", e);
|
||||
}
|
||||
catch (NoSuchPaddingException e)
|
||||
{
|
||||
throw new RuntimeException("Failed to get an instance of Cipher", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public InputMethodManager InputMethodManager
|
||||
{
|
||||
get { return (InputMethodManager) Context.GetSystemService(Context.InputMethodService); }
|
||||
}
|
||||
|
||||
public ISharedPreferences SharedPreferences
|
||||
{
|
||||
get { return PreferenceManager.GetDefaultSharedPreferences(Context); }
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class FingerprintCrypt: FingerprintManager.AuthenticationCallback, IFingerprintIdentifier
|
||||
{
|
||||
protected const string FailedToInitCipher = "Failed to init Cipher";
|
||||
public override void OnAuthenticationError(FingerprintState errorCode, ICharSequence errString)
|
||||
{
|
||||
Kp2aLog.Log("FP: OnAuthenticationError: " + errString + ", " + _selfCancelled);
|
||||
if (!_selfCancelled)
|
||||
_callback.OnAuthenticationError(errorCode, errString);
|
||||
}
|
||||
|
||||
public override void OnAuthenticationFailed()
|
||||
{
|
||||
Kp2aLog.Log("FP: OnAuthenticationFailed " + _selfCancelled);
|
||||
_callback.OnAuthenticationFailed();
|
||||
}
|
||||
|
||||
public override void OnAuthenticationHelp(FingerprintState helpCode, ICharSequence helpString)
|
||||
{
|
||||
_callback.OnAuthenticationHelp(helpCode, helpString);
|
||||
}
|
||||
|
||||
public override void OnAuthenticationSucceeded(FingerprintManager.AuthenticationResult result)
|
||||
{
|
||||
Kp2aLog.Log("FP: OnAuthenticationSucceeded ");
|
||||
StopListening();
|
||||
_callback.OnAuthenticationSucceeded(result);
|
||||
}
|
||||
|
||||
protected readonly string _keyId;
|
||||
|
||||
protected Cipher _cipher;
|
||||
private bool _selfCancelled;
|
||||
private CancellationSignal _cancellationSignal;
|
||||
protected FingerprintManager.CryptoObject _cryptoObject;
|
||||
private FingerprintManager.AuthenticationCallback _callback;
|
||||
protected KeyStore _keystore;
|
||||
|
||||
private FingerprintManager _fingerprintManager;
|
||||
|
||||
public FingerprintCrypt(FingerprintModule fingerprint, string keyId)
|
||||
{
|
||||
Kp2aLog.Log("FP: Create " + this.GetType().Name);
|
||||
_keyId = keyId;
|
||||
|
||||
_cipher = fingerprint.Cipher;
|
||||
_keystore = fingerprint.Keystore;
|
||||
|
||||
_fingerprintManager = fingerprint.FingerprintManager;
|
||||
|
||||
}
|
||||
|
||||
public abstract bool Init();
|
||||
|
||||
|
||||
protected static string GetAlias(string keyId)
|
||||
{
|
||||
return "keepass2android." + keyId;
|
||||
}
|
||||
protected static string GetIvPrefKey(string prefKey)
|
||||
{
|
||||
return prefKey + "_iv";
|
||||
}
|
||||
public bool IsFingerprintAuthAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
return _fingerprintManager.IsHardwareDetected
|
||||
&& _fingerprintManager.HasEnrolledFingerprints;
|
||||
}
|
||||
}
|
||||
|
||||
public void StartListening(Context ctx, IFingerprintAuthCallback callback)
|
||||
{
|
||||
StartListening(new FingerprintAuthCallbackAdapter(callback, ctx));
|
||||
}
|
||||
|
||||
public void StartListening(FingerprintManager.AuthenticationCallback callback)
|
||||
{
|
||||
if (!IsFingerprintAuthAvailable)
|
||||
return;
|
||||
|
||||
Kp2aLog.Log("FP: StartListening ");
|
||||
var thisSignal = new CancellationSignal();
|
||||
_cancellationSignal = thisSignal;
|
||||
_cancellationSignal.CancelEvent += (sender, args) =>
|
||||
{
|
||||
if (_cancellationSignal == thisSignal) _cancellationSignal = null;
|
||||
};
|
||||
_selfCancelled = false;
|
||||
_callback = callback;
|
||||
_fingerprintManager.Authenticate(_cryptoObject, _cancellationSignal, 0 /* flags */, this, null);
|
||||
|
||||
}
|
||||
|
||||
public void StopListening()
|
||||
{
|
||||
if (_cancellationSignal != null)
|
||||
{
|
||||
Kp2aLog.Log("FP: StopListening ");
|
||||
_selfCancelled = true;
|
||||
try
|
||||
{
|
||||
_cancellationSignal.Cancel();
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Kp2aLog.LogUnexpectedError(e);
|
||||
}
|
||||
_cancellationSignal = null;
|
||||
}
|
||||
}
|
||||
|
||||
public string Encrypt(string textToEncrypt)
|
||||
{
|
||||
Kp2aLog.Log("FP: Encrypting");
|
||||
return Base64.EncodeToString(_cipher.DoFinal(System.Text.Encoding.UTF8.GetBytes(textToEncrypt)), 0);
|
||||
}
|
||||
|
||||
|
||||
public void StoreEncrypted(string textToEncrypt, string prefKey, Context context)
|
||||
{
|
||||
var edit = PreferenceManager.GetDefaultSharedPreferences(context).Edit();
|
||||
StoreEncrypted(textToEncrypt, prefKey, edit);
|
||||
edit.Commit();
|
||||
}
|
||||
|
||||
public void StoreEncrypted(string textToEncrypt, string prefKey, ISharedPreferencesEditor edit)
|
||||
{
|
||||
edit.PutString(prefKey, Encrypt(textToEncrypt));
|
||||
edit.PutString(GetIvPrefKey(prefKey), Base64.EncodeToString(CipherIv, 0));
|
||||
|
||||
}
|
||||
|
||||
|
||||
private byte[] CipherIv
|
||||
{
|
||||
get { return _cipher.GetIV(); }
|
||||
}
|
||||
}
|
||||
|
||||
public interface IFingerprintIdentifier
|
||||
{
|
||||
bool Init();
|
||||
void StartListening(Context ctx, IFingerprintAuthCallback callback);
|
||||
void StopListening();
|
||||
}
|
||||
|
||||
public class FingerprintDecryption : FingerprintCrypt
|
||||
{
|
||||
private readonly Context _context;
|
||||
private readonly byte[] _iv;
|
||||
|
||||
|
||||
public FingerprintDecryption(FingerprintModule fingerprint, string keyId, byte[] iv) : base(fingerprint, keyId)
|
||||
{
|
||||
_iv = iv;
|
||||
}
|
||||
|
||||
public FingerprintDecryption(FingerprintModule fingerprint, string keyId, Context context, string prefKey)
|
||||
: base(fingerprint, keyId)
|
||||
{
|
||||
_context = context;
|
||||
_iv = Base64.Decode(PreferenceManager.GetDefaultSharedPreferences(context).GetString(GetIvPrefKey(prefKey), null), 0);
|
||||
}
|
||||
|
||||
public static bool IsSetUp(Context context, string prefKey)
|
||||
{
|
||||
return PreferenceManager.GetDefaultSharedPreferences(context).GetString(GetIvPrefKey(prefKey), null) != null;
|
||||
}
|
||||
|
||||
public override bool Init()
|
||||
{
|
||||
Kp2aLog.Log("FP: Init for Dec");
|
||||
try
|
||||
{
|
||||
_keystore.Load(null);
|
||||
var key = _keystore.GetKey(GetAlias(_keyId), null);
|
||||
var ivParams = new IvParameterSpec(_iv);
|
||||
_cipher.Init(CipherMode.DecryptMode, key, ivParams);
|
||||
|
||||
_cryptoObject = new FingerprintManager.CryptoObject(_cipher);
|
||||
return true;
|
||||
}
|
||||
catch (KeyPermanentlyInvalidatedException e)
|
||||
{
|
||||
Kp2aLog.Log("FP: KeyPermanentlyInvalidatedException." + e.ToString());
|
||||
return false;
|
||||
}
|
||||
catch (KeyStoreException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (CertificateException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (UnrecoverableKeyException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (InvalidKeyException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string Decrypt(string encryted)
|
||||
{
|
||||
Kp2aLog.Log("FP: Decrypting ");
|
||||
byte[] encryptedBytes = Base64.Decode(encryted, 0);
|
||||
return System.Text.Encoding.UTF8.GetString(_cipher.DoFinal(encryptedBytes));
|
||||
}
|
||||
|
||||
public string DecryptStored(string prefKey)
|
||||
{
|
||||
string enc = PreferenceManager.GetDefaultSharedPreferences(_context).GetString(prefKey, null);
|
||||
return Decrypt(enc);
|
||||
}
|
||||
}
|
||||
|
||||
public class FingerprintEncryption : FingerprintCrypt
|
||||
{
|
||||
|
||||
private KeyGenerator _keyGen;
|
||||
|
||||
|
||||
public FingerprintEncryption(FingerprintModule fingerprint, string keyId) :
|
||||
base(fingerprint, keyId)
|
||||
{
|
||||
_keyGen = fingerprint.KeyGenerator;
|
||||
Kp2aLog.Log("FP: CreateKey ");
|
||||
CreateKey();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a symmetric key in the Android Key Store which can only be used after the user
|
||||
/// has authenticated with fingerprint.
|
||||
/// </summary>
|
||||
private void CreateKey()
|
||||
{
|
||||
try
|
||||
{
|
||||
_keystore.Load(null);
|
||||
_keyGen.Init(new KeyGenParameterSpec.Builder(GetAlias(_keyId),
|
||||
KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
|
||||
.SetBlockModes(KeyProperties.BlockModeCbc)
|
||||
// Require the user to authenticate with a fingerprint to authorize every use
|
||||
// of the key
|
||||
.SetUserAuthenticationRequired(true)
|
||||
.SetEncryptionPaddings(KeyProperties.EncryptionPaddingPkcs7)
|
||||
.Build());
|
||||
_keyGen.GenerateKey();
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
catch (InvalidAlgorithmParameterException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
catch (CertificateException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Init()
|
||||
{
|
||||
Kp2aLog.Log("FP: Init for Enc ");
|
||||
try
|
||||
{
|
||||
_keystore.Load(null);
|
||||
var key = _keystore.GetKey(GetAlias(_keyId), null);
|
||||
_cipher.Init(CipherMode.EncryptMode, key);
|
||||
|
||||
_cryptoObject = new FingerprintManager.CryptoObject(_cipher);
|
||||
return true;
|
||||
}
|
||||
catch (KeyPermanentlyInvalidatedException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (KeyStoreException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (CertificateException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (UnrecoverableKeyException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
catch (InvalidKeyException e)
|
||||
{
|
||||
throw new RuntimeException(FailedToInitCipher, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FingerprintAuthCallbackAdapter : FingerprintManager.AuthenticationCallback
|
||||
{
|
||||
private readonly IFingerprintAuthCallback _callback;
|
||||
private readonly Context _context;
|
||||
|
||||
public FingerprintAuthCallbackAdapter(IFingerprintAuthCallback callback, Context context)
|
||||
{
|
||||
_callback = callback;
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public override void OnAuthenticationSucceeded(FingerprintManager.AuthenticationResult result)
|
||||
{
|
||||
_callback.OnFingerprintAuthSucceeded();
|
||||
}
|
||||
|
||||
public override void OnAuthenticationError(FingerprintState errorCode, ICharSequence errString)
|
||||
{
|
||||
_callback.OnFingerprintError(errString.ToString());
|
||||
}
|
||||
|
||||
public override void OnAuthenticationHelp(FingerprintState helpCode, ICharSequence helpString)
|
||||
{
|
||||
_callback.OnFingerprintError(helpString.ToString());
|
||||
}
|
||||
|
||||
public override void OnAuthenticationFailed()
|
||||
{
|
||||
_callback.OnFingerprintError(
|
||||
_context.Resources.GetString(Resource.String.fingerprint_not_recognized));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,7 +5,6 @@ using System.Text;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Hardware.Biometrics;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Util;
|
||||
@@ -17,15 +16,13 @@ using Java.Lang;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
class BiometrySamsungIdentifier: IBiometricIdentifier
|
||||
class FingerprintSamsungIdentifier: IFingerprintIdentifier
|
||||
{
|
||||
private readonly Context _context;
|
||||
SpassFingerprint _spassFingerprint;
|
||||
SpassFingerprint _spassFingerprint;
|
||||
Spass _spass;
|
||||
public BiometrySamsungIdentifier(Context context)
|
||||
public FingerprintSamsungIdentifier(Context context)
|
||||
{
|
||||
_context = context;
|
||||
_spass = new Spass();
|
||||
_spass = new Spass();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -64,12 +61,12 @@ namespace keepass2android
|
||||
}
|
||||
class IdentifyListener : Java.Lang.Object, IIdentifyListener
|
||||
{
|
||||
private readonly IBiometricAuthCallback _callback;
|
||||
private readonly IFingerprintAuthCallback _callback;
|
||||
private readonly Context _context;
|
||||
private readonly BiometrySamsungIdentifier _id;
|
||||
private readonly FingerprintSamsungIdentifier _id;
|
||||
|
||||
|
||||
public IdentifyListener(IBiometricAuthCallback callback, Context context, BiometrySamsungIdentifier id)
|
||||
public IdentifyListener(IFingerprintAuthCallback callback, Context context, FingerprintSamsungIdentifier id)
|
||||
{
|
||||
_callback = callback;
|
||||
_context = context;
|
||||
@@ -83,11 +80,11 @@ namespace keepass2android
|
||||
_id.Listening = false;
|
||||
if (responseCode == SpassFingerprint.StatusAuthentificationSuccess)
|
||||
{
|
||||
_callback.OnBiometricAuthSucceeded();
|
||||
_callback.OnFingerprintAuthSucceeded();
|
||||
}
|
||||
else if (responseCode == SpassFingerprint.StatusAuthentificationPasswordSuccess)
|
||||
{
|
||||
_callback.OnBiometricAuthSucceeded();
|
||||
_callback.OnFingerprintAuthSucceeded();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -109,22 +106,22 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
|
||||
public void StartListening(IBiometricAuthCallback callback)
|
||||
public void StartListening(Context ctx, IFingerprintAuthCallback callback)
|
||||
{
|
||||
if (Listening) return;
|
||||
|
||||
try
|
||||
{
|
||||
_spassFingerprint.StartIdentifyWithDialog(_context, new IdentifyListener(callback, _context, this), false);
|
||||
_spassFingerprint.StartIdentifyWithDialog(ctx, new IdentifyListener(callback, ctx, this), false);
|
||||
Listening = true;
|
||||
}
|
||||
catch (SpassInvalidStateException m)
|
||||
{
|
||||
callback.OnBiometricError(m.Message);
|
||||
callback.OnFingerprintError(m.Message);
|
||||
}
|
||||
catch (IllegalStateException ex)
|
||||
{
|
||||
callback.OnBiometricError(ex.Message);
|
||||
callback.OnFingerprintError(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,10 +141,5 @@ namespace keepass2android
|
||||
Kp2aLog.LogUnexpectedError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasUserInterface
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,16 +24,16 @@ namespace keepass2android
|
||||
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden,
|
||||
Theme = "@style/MyTheme_ActionBar", MainLauncher = false)]
|
||||
[IntentFilter(new[] { "kp2a.action.FingerprintSetupActivity" }, Categories = new[] { Intent.CategoryDefault })]
|
||||
public class BiometricSetupActivity : LockCloseActivity, IBiometricAuthCallback
|
||||
public class FingerprintSetupActivity : LockCloseActivity, IFingerprintAuthCallback
|
||||
{
|
||||
private readonly ActivityDesign _activityDesign;
|
||||
|
||||
public BiometricSetupActivity(IntPtr javaReference, JniHandleOwnership transfer)
|
||||
public FingerprintSetupActivity(IntPtr javaReference, JniHandleOwnership transfer)
|
||||
: base(javaReference, transfer)
|
||||
{
|
||||
_activityDesign = new ActivityDesign(this);
|
||||
}
|
||||
public BiometricSetupActivity()
|
||||
public FingerprintSetupActivity()
|
||||
{
|
||||
_activityDesign = new ActivityDesign(this);
|
||||
}
|
||||
@@ -42,7 +42,7 @@ namespace keepass2android
|
||||
|
||||
private FingerprintUnlockMode _unlockMode = FingerprintUnlockMode.Disabled;
|
||||
private FingerprintUnlockMode _desiredUnlockMode;
|
||||
private BiometricEncryption _enc;
|
||||
private FingerprintEncryption _enc;
|
||||
private RadioButton[] _radioButtons;
|
||||
public override bool OnOptionsItemSelected(IMenuItem item)
|
||||
{
|
||||
@@ -70,7 +70,6 @@ namespace keepass2android
|
||||
_fpIcon = FindViewById<ImageView>(Resource.Id.fingerprint_icon);
|
||||
_fpTextView = FindViewById<TextView>(Resource.Id.fingerprint_status);
|
||||
|
||||
|
||||
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
|
||||
SupportActionBar.SetHomeButtonEnabled(true);
|
||||
|
||||
@@ -119,27 +118,35 @@ 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.close_database_after_failed).Checked =
|
||||
Util.GetCloseDatabaseAfterFailedBiometricQuickUnlock(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();
|
||||
};
|
||||
if ((int)Build.VERSION.SdkInt >= 23)
|
||||
RequestPermissions(new[] {Manifest.Permission.UseFingerprint}, FingerprintPermissionRequestCode);
|
||||
else
|
||||
{
|
||||
TrySetupSamsung();
|
||||
|
||||
}
|
||||
|
||||
FindViewById<CheckBox>(Resource.Id.close_database_after_failed).CheckedChange += (sender, args) =>
|
||||
{
|
||||
PreferenceManager.GetDefaultSharedPreferences(this)
|
||||
.Edit()
|
||||
.PutBoolean(GetString(Resource.String.CloseDatabaseAfterFailedBiometricQuickUnlock_key), args.IsChecked)
|
||||
.Commit();
|
||||
};
|
||||
UpdateKeyboardCheckboxVisibility();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility();
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility()
|
||||
private void UpdateKeyboardCheckboxVisibility()
|
||||
{
|
||||
FindViewById(Resource.Id.close_database_after_failed).Visibility = _unlockMode == FingerprintUnlockMode.QuickUnlock ? ViewStates.Visible : ViewStates.Gone;
|
||||
FindViewById(Resource.Id.show_keyboard_while_fingerprint).Visibility = (_unlockMode == FingerprintUnlockMode.Disabled) ||
|
||||
(_samsungFingerprint != null)
|
||||
? ViewStates.Gone
|
||||
: ViewStates.Visible;
|
||||
}
|
||||
|
||||
private bool TrySetupSamsung()
|
||||
@@ -147,20 +154,20 @@ namespace keepass2android
|
||||
try
|
||||
{
|
||||
//try to create a Samsung ID object
|
||||
_samsungBiometry = new BiometrySamsungIdentifier(this);
|
||||
if (!_samsungBiometry.Init())
|
||||
_samsungFingerprint = new FingerprintSamsungIdentifier(this);
|
||||
if (!_samsungFingerprint.Init())
|
||||
{
|
||||
SetError(Resource.String.fingerprint_no_enrolled);
|
||||
}
|
||||
ShowRadioButtons();
|
||||
FindViewById(Resource.Id.container_fingerprint_unlock).Visibility = _samsungBiometry == null
|
||||
FindViewById(Resource.Id.container_fingerprint_unlock).Visibility = _samsungFingerprint == null
|
||||
? ViewStates.Visible
|
||||
: ViewStates.Gone;
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_samsungBiometry = null;
|
||||
_samsungFingerprint = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -224,7 +231,30 @@ namespace keepass2android
|
||||
tv.Visibility = ViewStates.Visible;
|
||||
}
|
||||
|
||||
|
||||
const int FingerprintPermissionRequestCode = 0;
|
||||
public override void OnRequestPermissionsResult (int requestCode, string[] permissions, Permission[] grantResults)
|
||||
{
|
||||
if (requestCode == FingerprintPermissionRequestCode && grantResults[0] == Permission.Granted)
|
||||
{
|
||||
FingerprintModule fpModule = new FingerprintModule(this);
|
||||
if (fpModule.FingerprintManager == null || (!fpModule.FingerprintManager.IsHardwareDetected))
|
||||
{
|
||||
//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();
|
||||
return;
|
||||
}
|
||||
if (!fpModule.FingerprintManager.HasEnrolledFingerprints)
|
||||
{
|
||||
SetError(Resource.String.fingerprint_no_enrolled);
|
||||
return;
|
||||
}
|
||||
ShowRadioButtons();
|
||||
UpdateKeyboardCheckboxVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowRadioButtons()
|
||||
{
|
||||
FindViewById<TextView>(Resource.Id.tvFatalError).Visibility = ViewStates.Gone;
|
||||
@@ -232,24 +262,17 @@ namespace keepass2android
|
||||
FindViewById(Resource.Id.fingerprint_auth_container).Visibility = ViewStates.Gone;
|
||||
}
|
||||
|
||||
private void HideRadioButtons()
|
||||
{
|
||||
FindViewById<TextView>(Resource.Id.tvFatalError).Visibility = ViewStates.Gone;
|
||||
FindViewById(Resource.Id.radio_buttons).Visibility = ViewStates.Gone;
|
||||
FindViewById(Resource.Id.fingerprint_auth_container).Visibility = ViewStates.Gone;
|
||||
}
|
||||
|
||||
|
||||
private void ChangeUnlockMode(FingerprintUnlockMode oldMode, FingerprintUnlockMode newMode)
|
||||
private void ChangeUnlockMode(FingerprintUnlockMode oldMode, FingerprintUnlockMode newMode)
|
||||
{
|
||||
if (oldMode == newMode)
|
||||
return;
|
||||
|
||||
|
||||
if (_samsungBiometry != null)
|
||||
if (_samsungFingerprint != null)
|
||||
{
|
||||
_unlockMode = newMode;
|
||||
UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility();
|
||||
UpdateKeyboardCheckboxVisibility();
|
||||
|
||||
ISharedPreferencesEditor edit = PreferenceManager.GetDefaultSharedPreferences(this).Edit();
|
||||
edit.PutString(App.Kp2a.CurrentDb.CurrentFingerprintModePrefKey, _unlockMode.ToString());
|
||||
@@ -260,26 +283,25 @@ namespace keepass2android
|
||||
if (newMode == FingerprintUnlockMode.Disabled)
|
||||
{
|
||||
_unlockMode = newMode;
|
||||
UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility();
|
||||
|
||||
StoreUnlockMode();
|
||||
UpdateKeyboardCheckboxVisibility();
|
||||
|
||||
StoreUnlockMode();
|
||||
return;
|
||||
}
|
||||
|
||||
_desiredUnlockMode = newMode;
|
||||
FindViewById(Resource.Id.radio_buttons).Visibility = ViewStates.Gone;
|
||||
UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility();
|
||||
FindViewById(Resource.Id.show_keyboard_while_fingerprint).Visibility = ViewStates.Gone;
|
||||
|
||||
FindViewById(Resource.Id.fingerprint_auth_container).Visibility = ViewStates.Visible;
|
||||
try
|
||||
FindViewById(Resource.Id.fingerprint_auth_container).Visibility = ViewStates.Visible;
|
||||
_enc = new FingerprintEncryption(new FingerprintModule(this), CurrentPreferenceKey);
|
||||
try
|
||||
{
|
||||
_enc = new BiometricEncryption(new BiometricModule(this), CurrentPreferenceKey);
|
||||
if (!_enc.Init())
|
||||
if (!_enc.Init())
|
||||
throw new Exception("Failed to initialize cipher");
|
||||
ResetErrorTextRunnable();
|
||||
|
||||
_enc.StartListening(new BiometricAuthCallbackAdapter(this, this));
|
||||
}
|
||||
_enc.StartListening(new FingerprintAuthCallbackAdapter(this, this));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CheckCurrentRadioButton();
|
||||
@@ -296,9 +318,9 @@ namespace keepass2android
|
||||
private ImageView _fpIcon;
|
||||
private TextView _fpTextView;
|
||||
|
||||
private BiometrySamsungIdentifier _samsungBiometry;
|
||||
private FingerprintSamsungIdentifier _samsungFingerprint;
|
||||
|
||||
public void OnBiometricAuthSucceeded()
|
||||
public void OnFingerprintAuthSucceeded()
|
||||
{
|
||||
_unlockMode = _desiredUnlockMode;
|
||||
|
||||
@@ -312,7 +334,7 @@ namespace keepass2android
|
||||
FindViewById(Resource.Id.fingerprint_auth_container).Visibility = ViewStates.Gone;
|
||||
|
||||
StoreUnlockMode();
|
||||
UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility();
|
||||
UpdateKeyboardCheckboxVisibility();
|
||||
|
||||
|
||||
}, SUCCESS_DELAY_MILLIS);
|
||||
@@ -322,7 +344,7 @@ namespace keepass2android
|
||||
|
||||
|
||||
|
||||
public void OnBiometricError(string error)
|
||||
public void OnFingerprintError(string error)
|
||||
{
|
||||
_fpIcon.SetImageResource(Resource.Drawable.ic_fingerprint_error);
|
||||
_fpTextView.Text = error;
|
||||
@@ -332,42 +354,20 @@ namespace keepass2android
|
||||
_fpTextView.PostDelayed(ResetErrorTextRunnable, ERROR_TIMEOUT_MILLIS);
|
||||
}
|
||||
|
||||
public void OnBiometricAttemptFailed(string message)
|
||||
{
|
||||
//ignore
|
||||
}
|
||||
|
||||
void ResetErrorTextRunnable()
|
||||
void ResetErrorTextRunnable()
|
||||
{
|
||||
_fpTextView.SetTextColor(
|
||||
_fpTextView.Resources.GetColor(Resource.Color.hint_color, null));
|
||||
_fpTextView.Text = "";
|
||||
_fpTextView.Text = _fpTextView.Resources.GetString(Resource.String.fingerprint_hint);
|
||||
_fpIcon.SetImageResource(Resource.Drawable.ic_fp_40px);
|
||||
}
|
||||
|
||||
protected override void OnResume()
|
||||
{
|
||||
base.OnResume();
|
||||
|
||||
BiometricModule fpModule = new BiometricModule(this);
|
||||
HideRadioButtons();
|
||||
if (!fpModule.IsHardwareAvailable)
|
||||
{
|
||||
//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);
|
||||
UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility();
|
||||
return;
|
||||
}
|
||||
if (!fpModule.IsAvailable)
|
||||
{
|
||||
SetError(Resource.String.fingerprint_no_enrolled);
|
||||
return;
|
||||
}
|
||||
ShowRadioButtons();
|
||||
UpdateCloseDatabaseAfterFailedBiometricQuickUnlockVisibility();
|
||||
|
||||
}
|
||||
if (_enc != null)
|
||||
_enc.StartListening(new FingerprintAuthCallbackAdapter(this, this));
|
||||
}
|
||||
|
||||
protected override void OnPause()
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
@@ -495,7 +495,7 @@ namespace keepass2android
|
||||
{
|
||||
FindViewById(Resource.Id.enable_fingerprint).Click += (sender, args) =>
|
||||
{
|
||||
StartActivity(typeof(BiometricSetupActivity));
|
||||
StartActivity(typeof(FingerprintSetupActivity));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -689,8 +689,8 @@ namespace keepass2android
|
||||
if (!disabledForAll && !disabledForDatabase && !App.Kp2a.IsChildDatabase(App.Kp2a.CurrentDb))
|
||||
{
|
||||
|
||||
BiometricModule biometricModule = new BiometricModule(this);
|
||||
if (biometricModule.IsAvailable)
|
||||
FingerprintModule fpModule = new FingerprintModule(this);
|
||||
if (fpModule.FingerprintManager != null && fpModule.FingerprintManager.IsHardwareDetected)
|
||||
{
|
||||
FingerprintUnlockMode um;
|
||||
Enum.TryParse(_prefs.GetString(Database.GetFingerprintModePrefKey(App.Kp2a.CurrentDb.Ioc), ""), out um);
|
||||
@@ -1239,7 +1239,7 @@ namespace keepass2android
|
||||
{
|
||||
Handler.Post(() =>
|
||||
{
|
||||
Toast.MakeText(ActiveActivity ?? Application.Context, "Unrecoverable error: " + Message, ToastLength.Long).Show();
|
||||
Toast.MakeText(ActiveActivity, "Unrecoverable error: " + Message, ToastLength.Long).Show();
|
||||
});
|
||||
|
||||
App.Kp2a.Lock(false);
|
||||
@@ -1390,7 +1390,7 @@ namespace keepass2android
|
||||
case Resource.Id.menu_copy:
|
||||
|
||||
var copyTask = new CopyEntry((GroupBaseActivity)Activity, App.Kp2a, (PwEntry)checkedItems.First(),
|
||||
new GroupBaseActivity.RefreshTask(handler, ((GroupBaseActivity)Activity)), App.Kp2a.CurrentDb);
|
||||
new GroupBaseActivity.RefreshTask(handler, ((GroupBaseActivity)Activity)));
|
||||
|
||||
ProgressTask pt = new ProgressTask(App.Kp2a, Activity, copyTask);
|
||||
pt.Run();
|
||||
|
||||
@@ -138,21 +138,14 @@ namespace keepass2android
|
||||
return keys.OrderBy(s => s, c);
|
||||
}
|
||||
|
||||
public override bool ShowAddAttachments
|
||||
{
|
||||
get
|
||||
{
|
||||
if (manualShowAddAttachments != null) return (bool)manualShowAddAttachments;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ShowAddExtras
|
||||
public override bool ShowAddAttachments
|
||||
{
|
||||
get {
|
||||
if (manualShowAddExtras != null) return (bool)manualShowAddExtras;
|
||||
return false;
|
||||
}
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool ShowAddExtras
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override string GetTitle(string key)
|
||||
|
||||
@@ -24,8 +24,8 @@ using Android.Support.V7.App;
|
||||
namespace keepass2android
|
||||
{
|
||||
|
||||
public abstract class LifecycleAwareActivity : AndroidX.AppCompat.App.AppCompatActivity
|
||||
{
|
||||
public abstract class LifecycleAwareActivity : AppCompatActivity
|
||||
{
|
||||
protected LifecycleAwareActivity (IntPtr javaReference, JniHandleOwnership transfer)
|
||||
: base(javaReference, transfer)
|
||||
{
|
||||
|
||||
@@ -54,9 +54,13 @@ namespace keepass2android
|
||||
{
|
||||
_design.ApplyTheme();
|
||||
base.OnCreate(savedInstanceState);
|
||||
|
||||
|
||||
|
||||
Util.MakeSecureDisplay(this);
|
||||
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(
|
||||
GetString(Resource.String.ViewDatabaseSecure_key), true))
|
||||
{
|
||||
Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
|
||||
}
|
||||
|
||||
|
||||
_ioc = App.Kp2a.CurrentDb?.Ioc;
|
||||
|
||||
@@ -43,9 +43,13 @@ namespace keepass2android
|
||||
{
|
||||
_design.ApplyTheme();
|
||||
base.OnCreate(savedInstanceState);
|
||||
|
||||
|
||||
|
||||
Util.MakeSecureDisplay(this);
|
||||
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(
|
||||
GetString(Resource.String.ViewDatabaseSecure_key), true))
|
||||
{
|
||||
Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
|
||||
}
|
||||
|
||||
_ioc = App.Kp2a.CurrentDb.Ioc;
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Content.PM;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Support.V7.App;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
[Activity(Label = AppNames.AppName, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden, Theme = "@style/MyTheme_Blue",
|
||||
LaunchMode = LaunchMode.SingleInstance)]
|
||||
public class NoSecureDisplayActivity : AndroidX.AppCompat.App.AppCompatActivity
|
||||
{
|
||||
private readonly ActivityDesign _design;
|
||||
|
||||
public NoSecureDisplayActivity()
|
||||
{
|
||||
_design = new ActivityDesign(this);
|
||||
}
|
||||
|
||||
protected override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
_design.ApplyTheme();
|
||||
base.OnCreate(savedInstanceState);
|
||||
SetContentView(Resource.Layout.no_secure_display_layout);
|
||||
FindViewById<Button>(Resource.Id.btn_goto_settings).Click += (sender, args) =>
|
||||
{
|
||||
AppSettingsActivity.Launch(this);
|
||||
};
|
||||
|
||||
var toolbar = FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.mytoolbar);
|
||||
|
||||
SetSupportActionBar(toolbar);
|
||||
|
||||
SupportActionBar.Title = AppNames.AppName;
|
||||
}
|
||||
|
||||
protected override void OnResume()
|
||||
{
|
||||
base.OnResume();
|
||||
_design.ReapplyTheme();
|
||||
//close if displays changed
|
||||
if (!Util.SecureDisplayConfigured(this) || !Util.HasUnsecureDisplay(this))
|
||||
Finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ namespace keepass2android
|
||||
LaunchMode = LaunchMode.SingleInstance,
|
||||
WindowSoftInputMode = SoftInput.AdjustResize,
|
||||
Theme = "@style/MyTheme_Blue")]
|
||||
public class PasswordActivity : LockingActivity, IBiometricAuthCallback
|
||||
public class PasswordActivity : LockingActivity, IFingerprintAuthCallback
|
||||
{
|
||||
|
||||
enum KeyProviders
|
||||
@@ -86,10 +86,8 @@ namespace keepass2android
|
||||
|
||||
public const String KeyKeyfile = "keyFile";
|
||||
public const String KeyPassword = "password";
|
||||
public const String LaunchImmediately = "launchImmediately";
|
||||
|
||||
|
||||
private const string ShowpasswordKey = "ShowPassword";
|
||||
private const string ShowpasswordKey = "ShowPassword";
|
||||
private const string KeyProviderIdOtp = "KP2A-OTP";
|
||||
private const string KeyProviderIdOtpRecovery = "KP2A-OTPSecret";
|
||||
private const string KeyProviderIdChallenge = "KP2A-Chal";
|
||||
@@ -575,13 +573,15 @@ namespace keepass2android
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int count = 1;
|
||||
|
||||
|
||||
private string mDrawerTitle;
|
||||
private MeasuringRelativeLayout.MeasureArgs _measureArgs;
|
||||
private ActivityDesign _activityDesign;
|
||||
private BiometricDecryption _biometricDec;
|
||||
private PasswordActivityBroadcastReceiver _intentReceiver;
|
||||
private FingerprintDecryption _fingerprintDec;
|
||||
private bool _fingerprintPermissionGranted;
|
||||
private PasswordActivityBroadcastReceiver _intentReceiver;
|
||||
private int _appnameclickCount;
|
||||
|
||||
|
||||
@@ -646,12 +646,16 @@ namespace keepass2android
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.AddAction(Intent.ActionScreenOff);
|
||||
RegisterReceiver(_intentReceiver, filter);
|
||||
|
||||
|
||||
//use FlagSecure to make sure the last (revealed) character of the master password is not visible in recent apps
|
||||
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(
|
||||
GetString(Resource.String.ViewDatabaseSecure_key), true))
|
||||
{
|
||||
Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
|
||||
}
|
||||
|
||||
|
||||
//use FlagSecure to make sure the last (revealed) character of the master password is not visible in recent apps
|
||||
Util.MakeSecureDisplay(this);
|
||||
|
||||
Intent i = Intent;
|
||||
Intent i = Intent;
|
||||
|
||||
|
||||
String action = i.Action;
|
||||
@@ -759,35 +763,19 @@ namespace keepass2android
|
||||
mDrawerTitle = Title;
|
||||
InitializeToolbarCollapsing();
|
||||
|
||||
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
|
||||
btn.Click += (sender, args) =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty((string)btn.Tag))
|
||||
{
|
||||
AlertDialog.Builder b = new AlertDialog.Builder(this);
|
||||
b.SetTitle(Resource.String.fingerprint_prefs);
|
||||
b.SetMessage(btn.Tag.ToString());
|
||||
b.SetPositiveButton(Android.Resource.String.Ok, (o, eventArgs) => ((Dialog)o).Dismiss());
|
||||
b.SetOnDismissListener(new Util.DismissListener(() => _biometricDec?.StartListening(this)));
|
||||
b.Show();
|
||||
}
|
||||
else _biometricDec?.StartListening(this);
|
||||
if ((int)Build.VERSION.SdkInt >= 23)
|
||||
RequestPermissions(new[] { Manifest.Permission.UseFingerprint }, FingerprintPermissionRequestCode);
|
||||
|
||||
};
|
||||
|
||||
|
||||
if (App.Kp2a.TrySelectCurrentDb(_ioConnection))
|
||||
|
||||
if (App.Kp2a.TrySelectCurrentDb(_ioConnection))
|
||||
{
|
||||
//database already opened. return the ioc and we're good.
|
||||
LaunchNextActivity();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Util.SetNoPersonalizedLearning(FindViewById<EditText>(Resource.Id.password_edit));
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void InitializeToolbarCollapsing()
|
||||
private void InitializeToolbarCollapsing()
|
||||
{
|
||||
var rootview = FindViewById<MeasuringRelativeLayout>(Resource.Id.relative_layout);
|
||||
rootview.ViewTreeObserver.GlobalLayout += (sender, args2) =>
|
||||
@@ -903,8 +891,41 @@ namespace keepass2android
|
||||
}
|
||||
}
|
||||
|
||||
const int FingerprintPermissionRequestCode = 99;
|
||||
|
||||
|
||||
|
||||
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
|
||||
{
|
||||
if ((requestCode == FingerprintPermissionRequestCode) && (grantResults.Length > 0) && (grantResults[0] == Permission.Granted))
|
||||
{
|
||||
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
|
||||
btn.Click += (sender, args) =>
|
||||
{
|
||||
AlertDialog.Builder b = new AlertDialog.Builder(this);
|
||||
b.SetTitle(Resource.String.fingerprint_prefs);
|
||||
b.SetMessage(btn.Tag.ToString());
|
||||
b.SetPositiveButton(Android.Resource.String.Ok, (o, eventArgs) => ((Dialog)o).Dismiss());
|
||||
if (_fingerprintDec != null)
|
||||
{
|
||||
b.SetNegativeButton(Resource.String.disable_sensor, (senderAlert, alertArgs) =>
|
||||
{
|
||||
btn.SetImageResource(Resource.Drawable.ic_fingerprint_error);
|
||||
_fingerprintDec?.StopListening();
|
||||
_fingerprintDec = null;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
b.SetNegativeButton(Resource.String.enable_sensor, (senderAlert, alertArgs) =>
|
||||
{
|
||||
InitFingerprintUnlock();
|
||||
});
|
||||
}
|
||||
b.Show();
|
||||
};
|
||||
_fingerprintPermissionGranted = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearFingerprintUnlockData()
|
||||
{
|
||||
@@ -914,7 +935,7 @@ namespace keepass2android
|
||||
edit.Commit();
|
||||
}
|
||||
|
||||
public void OnBiometricError(string message)
|
||||
public void OnFingerprintError(string message)
|
||||
{
|
||||
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
|
||||
|
||||
@@ -922,16 +943,12 @@ namespace keepass2android
|
||||
btn.PostDelayed(() =>
|
||||
{
|
||||
btn.SetImageResource(Resource.Drawable.ic_fp_40px);
|
||||
}, 1300);
|
||||
btn.Tag = GetString(Resource.String.fingerprint_unlock_hint);
|
||||
}, 1300);
|
||||
Toast.MakeText(this, message, ToastLength.Long).Show();
|
||||
}
|
||||
|
||||
public void OnBiometricAttemptFailed(string message)
|
||||
{
|
||||
//ignore
|
||||
}
|
||||
|
||||
public void OnBiometricAuthSucceeded()
|
||||
public void OnFingerprintAuthSucceeded()
|
||||
{
|
||||
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
|
||||
|
||||
@@ -939,7 +956,7 @@ namespace keepass2android
|
||||
|
||||
try
|
||||
{
|
||||
var masterPassword = _biometricDec.DecryptStored(Database.GetFingerprintPrefKey(_ioConnection));
|
||||
var masterPassword = _fingerprintDec.DecryptStored(Database.GetFingerprintPrefKey(_ioConnection));
|
||||
_password = FindViewById<EditText>(Resource.Id.password_edit).Text = masterPassword;
|
||||
FindViewById<EditText>(Resource.Id.password_edit).Enabled = false; //prevent accidental modification of password
|
||||
|
||||
@@ -1007,7 +1024,7 @@ namespace keepass2android
|
||||
|
||||
private void InitializeToolbar()
|
||||
{
|
||||
var toolbar = FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.mytoolbar);
|
||||
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar);
|
||||
|
||||
SetSupportActionBar(toolbar);
|
||||
|
||||
@@ -1364,9 +1381,11 @@ namespace keepass2android
|
||||
throw new NullPointerException("cpQuickUnlock");
|
||||
App.Kp2a.SetQuickUnlockEnabled(cbQuickUnlock.Checked);
|
||||
|
||||
if ((_loadDbFileTask != null) && (App.Kp2a.OfflineMode != _loadDbTaskOffline))
|
||||
if (App.Kp2a.OfflineMode != _loadDbTaskOffline)
|
||||
{
|
||||
if (App.Kp2a == null)
|
||||
if (_loadDbFileTask == null)
|
||||
throw new NullPointerException("_loadDbFileTask");
|
||||
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)
|
||||
@@ -1509,16 +1528,13 @@ namespace keepass2android
|
||||
|
||||
protected override void OnPause()
|
||||
{
|
||||
_biometricDec?.StopListening();
|
||||
_fingerprintDec?.StopListening();
|
||||
_lastOnPauseTime = DateTime.Now;
|
||||
|
||||
base.OnPause();
|
||||
}
|
||||
|
||||
private bool fingerprintInitialized;
|
||||
|
||||
|
||||
protected override void OnStart()
|
||||
protected override void OnStart()
|
||||
{
|
||||
base.OnStart();
|
||||
_starting = true;
|
||||
@@ -1530,14 +1546,9 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
DonateReminder.ShowDonateReminderIfAppropriate(this);
|
||||
|
||||
|
||||
if (compositeKeyForImmediateLoad == null && !fingerprintInitialized)
|
||||
{
|
||||
fingerprintInitialized = InitFingerprintUnlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private MemoryStream PreloadDbFile()
|
||||
{
|
||||
@@ -1762,19 +1773,30 @@ namespace keepass2android
|
||||
}
|
||||
else
|
||||
{
|
||||
bool showKeyboard = true;
|
||||
|
||||
|
||||
|
||||
bool showKeyboard = (Util.GetShowKeyboardDuringFingerprintUnlock(this));
|
||||
|
||||
|
||||
if (_fingerprintPermissionGranted)
|
||||
{
|
||||
if (!InitFingerprintUnlock())
|
||||
showKeyboard = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
FindViewById<ImageButton>(Resource.Id.fingerprintbtn).Visibility = ViewStates.Gone;
|
||||
showKeyboard = true;
|
||||
}
|
||||
|
||||
|
||||
EditText pwd = (EditText) FindViewById(Resource.Id.password_edit);
|
||||
pwd.PostDelayed(() =>
|
||||
{
|
||||
InputMethodManager keyboard = (InputMethodManager) GetSystemService(InputMethodService);
|
||||
if (showKeyboard)
|
||||
{
|
||||
pwd.RequestFocus();
|
||||
keyboard.ShowSoftInput(pwd, 0);
|
||||
}
|
||||
else
|
||||
if (showKeyboard)
|
||||
keyboard.ShowSoftInput(pwd, 0);
|
||||
else
|
||||
keyboard.HideSoftInputFromWindow(pwd.WindowToken, HideSoftInputFlags.ImplicitOnly);
|
||||
}, 50);
|
||||
}
|
||||
@@ -1843,14 +1865,16 @@ namespace keepass2android
|
||||
return false;
|
||||
}
|
||||
|
||||
BiometricModule fpModule = new BiometricModule(this);
|
||||
_biometricDec = new BiometricDecryption(fpModule, Database.GetFingerprintPrefKey(_ioConnection), this,
|
||||
FingerprintModule fpModule = new FingerprintModule(this);
|
||||
_fingerprintDec = new FingerprintDecryption(fpModule, Database.GetFingerprintPrefKey(_ioConnection), this,
|
||||
Database.GetFingerprintPrefKey(_ioConnection));
|
||||
|
||||
if (_biometricDec.Init())
|
||||
btn.Tag = GetString(Resource.String.fingerprint_unlock_hint);
|
||||
|
||||
if (_fingerprintDec.Init())
|
||||
{
|
||||
btn.SetImageResource(Resource.Drawable.ic_fp_40px);
|
||||
_biometricDec.StartListening(new BiometricAuthCallbackAdapter(this, this));
|
||||
_fingerprintDec.StartListening(new FingerprintAuthCallbackAdapter(this, this));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -1871,7 +1895,7 @@ namespace keepass2android
|
||||
|
||||
Toast.MakeText(this, Resource.String.fingerprint_reenable2, ToastLength.Long).Show();
|
||||
|
||||
_biometricDec = null;
|
||||
_fingerprintDec = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1884,7 +1908,7 @@ namespace keepass2android
|
||||
//key invalidated permanently
|
||||
btn.SetImageResource(Resource.Drawable.ic_fingerprint_error);
|
||||
btn.Tag = GetString(Resource.String.fingerprint_unlock_failed) + " " + GetString(Resource.String.fingerprint_reenable2);
|
||||
_biometricDec = null;
|
||||
_fingerprintDec = null;
|
||||
|
||||
ClearFingerprintUnlockData();
|
||||
}
|
||||
@@ -2123,7 +2147,7 @@ namespace keepass2android
|
||||
KeyProviderQueryContext ctx = new KeyProviderQueryContext(_act._ioConnection, false, false);
|
||||
|
||||
if (!OathHotpKeyProv.CreateAuxFile(_act._otpInfo, ctx, _act._otpAuxIoc))
|
||||
ShowError(_act.GetString(Resource.String.ErrorUpdatingOtpAuxFile));
|
||||
Toast.MakeText(_act, _act.GetString(Resource.String.ErrorUpdatingOtpAuxFile), ToastLength.Long).Show();
|
||||
|
||||
|
||||
}
|
||||
@@ -2131,7 +2155,8 @@ namespace keepass2android
|
||||
{
|
||||
Kp2aLog.LogUnexpectedError(e);
|
||||
|
||||
ShowError( _act.GetString(Resource.String.ErrorUpdatingOtpAuxFile) + " " + e.Message);
|
||||
Toast.MakeText(_act, _act.GetString(Resource.String.ErrorUpdatingOtpAuxFile) + " " + e.Message,
|
||||
ToastLength.Long).Show();
|
||||
}
|
||||
|
||||
|
||||
@@ -2144,11 +2169,7 @@ namespace keepass2android
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void ShowError(string message)
|
||||
{
|
||||
App.Kp2a.ShowToast(message);
|
||||
}
|
||||
|
||||
}
|
||||
private class PasswordActivityBroadcastReceiver : BroadcastReceiver
|
||||
{
|
||||
@@ -2171,8 +2192,8 @@ namespace keepass2android
|
||||
|
||||
private void OnScreenLocked()
|
||||
{
|
||||
if (_biometricDec != null)
|
||||
_biometricDec.StopListening();
|
||||
if (_fingerprintDec != null)
|
||||
_fingerprintDec.StopListening();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="46" android:versionName="0.9.3-release-3" package="keepass2android.keepass2android_debug" android:installLocation="auto">
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="29" />
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26" />
|
||||
<permission android:description="@string/permission_desc2" android:icon="@drawable/ic_notify_locked" android:label="KP2A entry search" android:name="keepass2android.keepass2android_debug.permission.KP2aInternalSearch" android:protectionLevel="signature" />
|
||||
<permission android:description="@string/permission_desc3" android:icon="@drawable/ic_launcher" android:label="KP2A choose autofill dataset" android:name="keepass2android.keepass2android_debug.permission.Kp2aChooseAutofill" android:protectionLevel="signature" />
|
||||
<application android:label="keepass2android"
|
||||
@@ -80,112 +80,34 @@
|
||||
</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/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 android:label="@string/kp2a_findUrl">
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
@@ -213,7 +135,6 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
|
||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
|
||||
<uses-permission android:name="keepass2android.keepass2android_debug.permission.KP2aInternalFileBrowsing" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
<!-- Samsung Pass permission -->
|
||||
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="147"
|
||||
android:versionName="1.08-r1"
|
||||
android:versionCode="141"
|
||||
android:versionName="1.07b-r0"
|
||||
package="keepass2android.keepass2android"
|
||||
android:installLocation="auto">
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="29" />
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26" />
|
||||
<permission android:description="@string/permission_desc2" android:icon="@drawable/ic_launcher" android:label="KP2A entry search" android:name="keepass2android.keepass2android.permission.KP2aInternalSearch" android:protectionLevel="signature" />
|
||||
<permission android:description="@string/permission_desc3" android:icon="@drawable/ic_launcher" android:label="KP2A choose autofill dataset" android:name="keepass2android.keepass2android.permission.Kp2aChooseAutofill" android:protectionLevel="signature" />
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
<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" />
|
||||
@@ -94,79 +95,13 @@
|
||||
|
||||
<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="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:scheme="content" />
|
||||
<data android:mimeType="*/*" />
|
||||
<data android:host="*" />
|
||||
<data android:pathPattern=".*\\.kdbp" />
|
||||
@@ -200,8 +135,7 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdb" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter android:label="@string/kp2a_findUrl">
|
||||
<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" />
|
||||
@@ -229,7 +163,6 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
|
||||
<uses-permission android:name="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing" />
|
||||
<uses-permission android:name="keepass2android.keepass2android.permission.KP2aInternalSearch" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
|
||||
<!-- Samsung Pass permission -->
|
||||
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="93"
|
||||
android:versionName="1.01-g"
|
||||
android:versionCode="141"
|
||||
android:versionName="1.07b-r0"
|
||||
package="keepass2android.keepass2android_nonet"
|
||||
android:installLocation="auto">
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="29" />
|
||||
<permission android:description="@string/permission_desc2" android:icon="@drawable/ic_launcher" android:label="KP2A entry search" android:name="keepass2android.keepass2android_nonet.permission.KP2aInternalSearch" android:protectionLevel="signature" />
|
||||
<permission android:description="@string/permission_desc3" android:icon="@drawable/ic_launcher" android:label="KP2A choose autofill dataset" android:name="keepass2android.keepass2android_nonet.permission.Kp2aChooseAutofill" android:protectionLevel="signature" />
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26" />
|
||||
<permission android:description="@string/permission_desc2" android:icon="@drawable/ic_launcher_offline" android:label="KP2A entry search" android:name="keepass2android.keepass2android_nonet.permission.KP2aInternalSearch" android:protectionLevel="signature" />
|
||||
<permission android:description="@string/permission_desc3" android:icon="@drawable/ic_launcher_offline" android:label="KP2A choose autofill dataset" android:name="keepass2android.keepass2android_nonet.permission.Kp2aChooseAutofill" android:protectionLevel="signature" />
|
||||
<application
|
||||
android:label="keepass2android"
|
||||
android:icon="@mipmap/ic_launcher_offline"
|
||||
@@ -44,7 +44,6 @@
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:configChanges="orientation|keyboard|keyboardHidden" android:label="@string/app_name" android:theme="@style/MyTheme_Blue" android:name="keepass2android.SelectCurrentDbActivity" android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
@@ -54,12 +53,13 @@
|
||||
<data android:mimeType="application/octet-stream" />
|
||||
<data android:host="*" />
|
||||
</intent-filter>
|
||||
|
||||
|
||||
<intent-filter>
|
||||
<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" />
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||
@@ -69,78 +69,12 @@
|
||||
<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="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:scheme="content" />
|
||||
<data android:mimeType="*/*" />
|
||||
<data android:host="*" />
|
||||
<data android:pathPattern=".*\\.kdbp" />
|
||||
@@ -174,7 +108,6 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
|
||||
<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"/>
|
||||
@@ -204,11 +137,9 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
|
||||
|
||||
<uses-permission android:name="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing" />
|
||||
<uses-permission android:name="keepass2android.keepass2android.permission.KP2aInternalSearch" />
|
||||
<uses-permission android:name="keepass2android.keepass2android_nonet.permission.KP2aInternalFileBrowsing" />
|
||||
<uses-permission android:name="keepass2android.keepass2android_nonet.permission.KP2aInternalSearch" />
|
||||
<!-- Samsung Pass permission -->
|
||||
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
|
||||
</manifest>
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace keepass2android
|
||||
String nameX = x.Strings.ReadSafe(PwDefs.TitleField);
|
||||
String nameY = y.Strings.ReadSafe(PwDefs.TitleField);
|
||||
if (nameX.ToLower() != nameY.ToLower())
|
||||
return String.Compare(nameX, nameY, StringComparison.CurrentCultureIgnoreCase);
|
||||
return String.Compare(nameX, nameY, StringComparison.OrdinalIgnoreCase);
|
||||
else
|
||||
{
|
||||
if (PwDefs.IsTanEntry(x) && PwDefs.IsTanEntry(y))
|
||||
@@ -138,7 +138,7 @@ namespace keepass2android
|
||||
{
|
||||
//ignore
|
||||
}
|
||||
return String.Compare(userX, userY, StringComparison.CurrentCultureIgnoreCase);
|
||||
return String.Compare(userX, userY, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace keepass2android
|
||||
|
||||
public int CompareGroups(PwGroup a, PwGroup b)
|
||||
{
|
||||
return String.Compare(a.Name, b.Name, StringComparison.CurrentCultureIgnoreCase);
|
||||
return String.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = ShowUserNotificationsMode.WhenTotp};
|
||||
var task = new SearchUrlTask() {UrlToSearchFor = _requestedUrl, ShowUserNotifications = false};
|
||||
task.ToIntent(i);
|
||||
StartActivityForResult(i, RequestCodeQuery);
|
||||
_startedQuery = true;
|
||||
|
||||
@@ -38,20 +38,17 @@ namespace keepass2android
|
||||
WindowSoftInputMode = SoftInput.AdjustResize,
|
||||
MainLauncher = false,
|
||||
Theme = "@style/MyTheme_Blue")]
|
||||
public class QuickUnlock : LifecycleAwareActivity, IBiometricAuthCallback
|
||||
public class QuickUnlock : LifecycleAwareActivity, IFingerprintAuthCallback
|
||||
{
|
||||
private IOConnectionInfo _ioc;
|
||||
private QuickUnlockBroadcastReceiver _intentReceiver;
|
||||
private ActivityDesign _design;
|
||||
private bool _fingerprintPermissionGranted;
|
||||
private IBiometricIdentifier _biometryIdentifier;
|
||||
private IFingerprintIdentifier _fingerprintIdentifier;
|
||||
private int _quickUnlockLength;
|
||||
private const int FingerprintPermissionRequestCode = 0;
|
||||
|
||||
private int numFailedAttempts = 0;
|
||||
private int maxNumFailedAttempts = int.MaxValue;
|
||||
|
||||
public QuickUnlock()
|
||||
public QuickUnlock()
|
||||
{
|
||||
_design = new ActivityDesign(this);
|
||||
}
|
||||
@@ -62,13 +59,15 @@ namespace keepass2android
|
||||
base.OnCreate(bundle);
|
||||
|
||||
//use FlagSecure to make sure the last (revealed) character of the password is not visible in recent apps
|
||||
Util.MakeSecureDisplay(this);
|
||||
if (PreferenceManager.GetDefaultSharedPreferences(this).GetBoolean(
|
||||
GetString(Resource.String.ViewDatabaseSecure_key), true))
|
||||
{
|
||||
Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);
|
||||
}
|
||||
|
||||
_ioc = App.Kp2a.GetDbForQuickUnlock()?.Ioc;
|
||||
|
||||
|
||||
|
||||
if (_ioc == null)
|
||||
if (_ioc == null)
|
||||
{
|
||||
Finish();
|
||||
return;
|
||||
@@ -76,7 +75,7 @@ namespace keepass2android
|
||||
|
||||
SetContentView(Resource.Layout.QuickUnlock);
|
||||
|
||||
var toolbar = FindViewById<AndroidX.AppCompat.Widget.Toolbar>(Resource.Id.mytoolbar);
|
||||
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.mytoolbar);
|
||||
|
||||
SetSupportActionBar(toolbar);
|
||||
|
||||
@@ -150,34 +149,70 @@ namespace keepass2android
|
||||
filter.AddAction(Intents.DatabaseLocked);
|
||||
RegisterReceiver(_intentReceiver, filter);
|
||||
|
||||
Util.SetNoPersonalizedLearning(FindViewById<EditText>(Resource.Id.QuickUnlock_password));
|
||||
if ((int) Build.VERSION.SdkInt >= 23)
|
||||
{
|
||||
Kp2aLog.Log("requesting fingerprint permission");
|
||||
RequestPermissions(new[] { Manifest.Permission.UseFingerprint }, FingerprintPermissionRequestCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (bundle != null)
|
||||
numFailedAttempts = bundle.GetInt(NumFailedAttemptsKey, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private const string NumFailedAttemptsKey = "FailedAttempts";
|
||||
|
||||
protected override void OnSaveInstanceState(Bundle outState)
|
||||
{
|
||||
base.OnSaveInstanceState(outState);
|
||||
outState.PutInt(NumFailedAttemptsKey, numFailedAttempts);
|
||||
|
||||
}
|
||||
|
||||
protected override void OnStart()
|
||||
protected override void OnStart()
|
||||
{
|
||||
base.OnStart();
|
||||
DonateReminder.ShowDonateReminderIfAppropriate(this);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
|
||||
{
|
||||
Kp2aLog.Log("OnRequestPermissionsResult " + (requestCode == FingerprintPermissionRequestCode) +
|
||||
((grantResults.Length > 0) && (grantResults[0] == Permission.Granted)));
|
||||
|
||||
if ((requestCode == FingerprintPermissionRequestCode) && (grantResults.Length > 0) && (grantResults[0] == Permission.Granted))
|
||||
{
|
||||
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
|
||||
btn.Click += (sender, args) =>
|
||||
{
|
||||
AlertDialog.Builder b = new AlertDialog.Builder(this);
|
||||
b.SetTitle(Resource.String.fingerprint_prefs);
|
||||
b.SetMessage(btn.Tag.ToString());
|
||||
b.SetPositiveButton(Android.Resource.String.Ok, (o, eventArgs) => ((Dialog)o).Dismiss());
|
||||
if (_fingerprintIdentifier != null)
|
||||
{
|
||||
b.SetNegativeButton(Resource.String.disable_sensor, (senderAlert, alertArgs) =>
|
||||
{
|
||||
btn.SetImageResource(Resource.Drawable.ic_fingerprint_error);
|
||||
_fingerprintIdentifier?.StopListening();
|
||||
_fingerprintIdentifier = null;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
b.SetNegativeButton(Resource.String.enable_sensor, (senderAlert, alertArgs) =>
|
||||
{
|
||||
InitFingerprintUnlock();
|
||||
});
|
||||
}
|
||||
b.Show();
|
||||
};
|
||||
_fingerprintPermissionGranted = true;
|
||||
Kp2aLog.Log("_fingerprintPermissionGranted");
|
||||
if (_onResumeDone)
|
||||
{
|
||||
//it seems the permission result is called after onResume sometimes. Repeat fingerprint unlock then.
|
||||
InitFingerprintUnlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnBiometricError(string message)
|
||||
bool _onResumeDone = false;
|
||||
|
||||
public void OnFingerprintError(string message)
|
||||
{
|
||||
Kp2aLog.Log("fingerprint error: " + message);
|
||||
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
|
||||
@@ -186,26 +221,15 @@ namespace keepass2android
|
||||
btn.PostDelayed(() =>
|
||||
{
|
||||
btn.SetImageResource(Resource.Drawable.ic_fp_40px);
|
||||
|
||||
btn.Tag = GetString(Resource.String.fingerprint_unlock_hint);
|
||||
}, 1300);
|
||||
Toast.MakeText(this, message, ToastLength.Long).Show();
|
||||
}
|
||||
|
||||
|
||||
public void OnBiometricAttemptFailed(string message)
|
||||
{
|
||||
numFailedAttempts++;
|
||||
if (numFailedAttempts >= maxNumFailedAttempts)
|
||||
{
|
||||
FindViewById<ImageButton>(Resource.Id.fingerprintbtn).Visibility = ViewStates.Gone;
|
||||
_biometryIdentifier.StopListening();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnBiometricAuthSucceeded()
|
||||
public void OnFingerprintAuthSucceeded()
|
||||
{
|
||||
Kp2aLog.Log("OnFingerprintAuthSucceeded");
|
||||
_biometryIdentifier.StopListening();
|
||||
_fingerprintIdentifier.StopListening();
|
||||
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
|
||||
|
||||
btn.SetImageResource(Resource.Drawable.ic_fingerprint_success);
|
||||
@@ -226,7 +250,7 @@ namespace keepass2android
|
||||
{
|
||||
Kp2aLog.Log("InitFingerprintUnlock");
|
||||
|
||||
if (_biometryIdentifier != null)
|
||||
if (_fingerprintIdentifier != null)
|
||||
{
|
||||
Kp2aLog.Log("Already listening for fingerprint!");
|
||||
return true;
|
||||
@@ -242,60 +266,49 @@ namespace keepass2android
|
||||
|
||||
if (um == FingerprintUnlockMode.Disabled)
|
||||
{
|
||||
_biometryIdentifier = null;
|
||||
_fingerprintIdentifier = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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,
|
||||
App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey);
|
||||
|
||||
if ((_biometryIdentifier == null) && (!BiometricDecryption.IsSetUp(this, App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey)))
|
||||
if (_fingerprintPermissionGranted)
|
||||
{
|
||||
FingerprintModule fpModule = new FingerprintModule(this);
|
||||
Kp2aLog.Log("fpModule.FingerprintManager.IsHardwareDetected=" + fpModule.FingerprintManager.IsHardwareDetected);
|
||||
if (fpModule.FingerprintManager.IsHardwareDetected) //see FingerprintSetupActivity
|
||||
_fingerprintIdentifier = new FingerprintDecryption(fpModule, App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey, this,
|
||||
App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey);
|
||||
}
|
||||
if ((_fingerprintIdentifier == null) && (!FingerprintDecryption.IsSetUp(this, App.Kp2a.GetDbForQuickUnlock().CurrentFingerprintPrefKey)))
|
||||
{
|
||||
try
|
||||
{
|
||||
Kp2aLog.Log("trying Samsung Fingerprint API...");
|
||||
_biometryIdentifier = new BiometrySamsungIdentifier(this);
|
||||
_fingerprintIdentifier = new FingerprintSamsungIdentifier(this);
|
||||
btn.Click += (sender, args) =>
|
||||
{
|
||||
if (_biometryIdentifier.Init())
|
||||
{
|
||||
if (numFailedAttempts < maxNumFailedAttempts)
|
||||
{
|
||||
_biometryIdentifier.StartListening(this);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
if (_fingerprintIdentifier.Init())
|
||||
_fingerprintIdentifier.StartListening(this, this);
|
||||
};
|
||||
Kp2aLog.Log("trying Samsung Fingerprint API...Seems to work!");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Kp2aLog.Log("trying Samsung Fingerprint API...failed.");
|
||||
_biometryIdentifier = null;
|
||||
_fingerprintIdentifier = null;
|
||||
}
|
||||
}
|
||||
if (_biometryIdentifier == null)
|
||||
if (_fingerprintIdentifier == null)
|
||||
{
|
||||
FindViewById<ImageButton>(Resource.Id.fingerprintbtn).Visibility = ViewStates.Gone;
|
||||
return false;
|
||||
}
|
||||
|
||||
btn.Tag = GetString(Resource.String.fingerprint_unlock_hint);
|
||||
|
||||
if (_biometryIdentifier.Init())
|
||||
if (_fingerprintIdentifier.Init())
|
||||
{
|
||||
Kp2aLog.Log("successfully initialized fingerprint.");
|
||||
btn.SetImageResource(Resource.Drawable.ic_fp_40px);
|
||||
_biometryIdentifier.StartListening(this);
|
||||
_fingerprintIdentifier.StartListening(this, this);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -310,7 +323,7 @@ namespace keepass2android
|
||||
btn.SetImageResource(Resource.Drawable.ic_fingerprint_error);
|
||||
btn.Tag = "Error initializing Fingerprint Unlock: " + e;
|
||||
|
||||
_biometryIdentifier = null;
|
||||
_fingerprintIdentifier = null;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -322,7 +335,7 @@ namespace keepass2android
|
||||
//key invalidated permanently
|
||||
btn.SetImageResource(Resource.Drawable.ic_fingerprint_error);
|
||||
btn.Tag = GetString(Resource.String.fingerprint_unlock_failed) + " " + GetString(Resource.String.fingerprint_reenable2);
|
||||
_biometryIdentifier = null;
|
||||
_fingerprintIdentifier = null;
|
||||
}
|
||||
|
||||
private void OnUnlock(int quickUnlockLength, EditText pwd)
|
||||
@@ -371,9 +384,8 @@ namespace keepass2android
|
||||
|
||||
CheckIfUnloaded();
|
||||
|
||||
InitFingerprintUnlock();
|
||||
|
||||
bool showKeyboard = true;
|
||||
bool showKeyboard = ((!InitFingerprintUnlock()) || (Util.GetShowKeyboardDuringFingerprintUnlock(this)));
|
||||
|
||||
EditText pwd = (EditText)FindViewById(Resource.Id.QuickUnlock_password);
|
||||
pwd.PostDelayed(() =>
|
||||
@@ -385,59 +397,25 @@ namespace keepass2android
|
||||
keyboard.HideSoftInputFromWindow(pwd.WindowToken, HideSoftInputFlags.ImplicitOnly);
|
||||
}, 50);
|
||||
|
||||
|
||||
var btn = FindViewById<ImageButton>(Resource.Id.fingerprintbtn);
|
||||
btn.Click += (sender, args) =>
|
||||
{
|
||||
if ((_biometryIdentifier != null) && ((_biometryIdentifier.HasUserInterface)|| string.IsNullOrEmpty((string)btn.Tag) ))
|
||||
{
|
||||
_biometryIdentifier.StartListening(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
AlertDialog.Builder b = new AlertDialog.Builder(this);
|
||||
b.SetTitle(Resource.String.fingerprint_prefs);
|
||||
b.SetMessage(btn.Tag.ToString());
|
||||
b.SetPositiveButton(Android.Resource.String.Ok, (o, eventArgs) => ((Dialog)o).Dismiss());
|
||||
if (_biometryIdentifier != null)
|
||||
{
|
||||
b.SetNegativeButton(Resource.String.disable_sensor, (senderAlert, alertArgs) =>
|
||||
{
|
||||
btn.SetImageResource(Resource.Drawable.ic_fingerprint_error);
|
||||
_biometryIdentifier?.StopListening();
|
||||
_biometryIdentifier = null;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
b.SetNegativeButton(Resource.String.enable_sensor, (senderAlert, alertArgs) =>
|
||||
{
|
||||
InitFingerprintUnlock();
|
||||
});
|
||||
}
|
||||
b.Show();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
_onResumeDone = true;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected override void OnPause()
|
||||
{
|
||||
if (_biometryIdentifier != null && !_biometryIdentifier.HasUserInterface)
|
||||
if (_fingerprintIdentifier != null)
|
||||
{
|
||||
Kp2aLog.Log("FP: Stop listening");
|
||||
_biometryIdentifier.StopListening();
|
||||
}
|
||||
_fingerprintIdentifier.StopListening();
|
||||
_fingerprintIdentifier = null;
|
||||
}
|
||||
|
||||
base.OnPause();
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.9 KiB |
@@ -92,7 +92,7 @@ android:fitsSystemWindows="true">
|
||||
android:textSize="10sp"
|
||||
android:text="/storage/emulated/0/keepass/keepass/database.kdbx" />
|
||||
</RelativeLayout>
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/mytoolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
android:fitsSystemWindows="true"
|
||||
android:layout_height="fill_parent"
|
||||
android:gravity="center_horizontal">
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/mytoolbar"
|
||||
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:id="@+id/root"
|
||||
android:layout_margin="12dip">
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user