initial release 0.5.0 BETA

This commit is contained in:
PhilippC
2013-02-23 17:43:42 +01:00
parent 36c1df19d4
commit 19f7dcf26d
439 changed files with 19770 additions and 153 deletions

104
src/KeePass.sln Normal file
View File

@@ -0,0 +1,104 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassLib2Android", "KeePassLib2Android\KeePassLib2Android.csproj", "{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "keepass2android", "keepass2android\keepass2android.csproj", "{A6CF8A86-37C1-4197-80FE-519DE2C842F5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
Release|Mixed Platforms = Release|Mixed Platforms
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Debug|Any CPU.Build.0 = Debug|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Debug|Win32.ActiveCfg = Debug|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Debug|Win32.Build.0 = Debug|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Debug|x64.ActiveCfg = Debug|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Debug|x64.Build.0 = Debug|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Release|Any CPU.ActiveCfg = Release|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Release|Any CPU.Build.0 = Release|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Release|Win32.ActiveCfg = Release|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Release|Win32.Build.0 = Release|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Release|x64.ActiveCfg = Release|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.Release|x64.Build.0 = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Win32.ActiveCfg = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Win32.Build.0 = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|x64.ActiveCfg = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|x64.Build.0 = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Any CPU.Build.0 = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Win32.ActiveCfg = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Win32.Build.0 = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|x64.ActiveCfg = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = keepass2android\keepass2android.csproj
Policies = $0
$0.DotNetNamingPolicy = $1
$1.DirectoryNamespaceAssociation = None
$1.ResourceNamePolicy = FileFormatDefault
$0.TextStylePolicy = $2
$2.FileWidth = 120
$2.TabsToSpaces = False
$2.inheritsSet = VisualStudio
$2.inheritsScope = text/plain
$2.scope = text/x-csharp
$0.CSharpFormattingPolicy = $3
$3.IndentSwitchBody = True
$3.AnonymousMethodBraceStyle = NextLine
$3.PropertyBraceStyle = NextLine
$3.PropertyGetBraceStyle = NextLine
$3.PropertySetBraceStyle = NextLine
$3.EventBraceStyle = NextLine
$3.EventAddBraceStyle = NextLine
$3.EventRemoveBraceStyle = NextLine
$3.StatementBraceStyle = NextLine
$3.ArrayInitializerBraceStyle = NextLine
$3.BeforeMethodDeclarationParentheses = False
$3.BeforeMethodCallParentheses = False
$3.BeforeConstructorDeclarationParentheses = False
$3.BeforeDelegateDeclarationParentheses = False
$3.NewParentheses = False
$3.inheritsSet = Mono
$3.inheritsScope = text/x-csharp
$3.scope = text/x-csharp
$0.TextStylePolicy = $4
$4.FileWidth = 120
$4.TabsToSpaces = False
$4.inheritsSet = VisualStudio
$4.inheritsScope = text/plain
$4.scope = text/plain
$0.TextStylePolicy = $5
$5.inheritsSet = null
$5.scope = application/xml
$0.XmlFormattingPolicy = $6
$6.inheritsSet = Mono
$6.inheritsScope = application/xml
$6.scope = application/xml
$0.StandardHeader = $7
$7.Text = @/*\nThis file is part of Keepass2Android, Copyright 2013 Philipp Crocoll.\n\n Keepass2Android is free software: you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation, either version 2 of the License, or\n (at your option) any later version.\n\n Keepass2Android is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU General Public License for more details.\n\n You should have received a copy of the GNU General Public License\n along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.\n */\n
$7.IncludeInNewFiles = True
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,7 +24,6 @@ using System.Security;
using System.Security.Cryptography;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms;
using System.Drawing;
using KeePassLib.Native;
@@ -137,13 +138,6 @@ namespace KeePassLib.Cryptography
pb = TimeUtil.PackTime(DateTime.Now);
ms.Write(pb, 0, pb.Length);
#if !KeePassLibSD
Point pt = Cursor.Position;
pb = MemUtil.UInt32ToBytes((uint)pt.X);
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt32ToBytes((uint)pt.Y);
ms.Write(pb, 0, pb.Length);
#endif
pb = MemUtil.UInt32ToBytes((uint)rWeak.Next());
ms.Write(pb, 0, pb.Length);

View File

@@ -41,6 +41,8 @@
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Mono.Android" />
<Reference Include="OpenTK-1.0" />
<Reference Include="Mono.Security" />
</ItemGroup>
<ItemGroup>
<Compile Include="Resources\Resource.designer.cs" />

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -71,7 +73,7 @@ namespace KeePassLib.Keys
private void Construct(IOConnectionInfo iocFile)
{
byte[] pbFileData = IOConnection.ReadFile(iocFile);
if(pbFileData == null) throw new FileNotFoundException();
if(pbFileData == null) throw new Java.IO.FileNotFoundException();
byte[] pbKey = LoadXmlKeyFile(pbFileData);
if(pbKey == null) pbKey = LoadKeyFile(pbFileData);

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -59,18 +61,7 @@ namespace KeePassLib.Keys
/// </summary>
public KcpUserAccount()
{
// Test if ProtectedData is supported -- throws an exception
// when running on an old system (Windows 98 / ME).
byte[] pbDummyData = new byte[128];
ProtectedData.Protect(pbDummyData, m_pbEntropy,
DataProtectionScope.CurrentUser);
byte[] pbKey = LoadUserKey(false);
if(pbKey == null) pbKey = CreateUserKey();
if(pbKey == null) throw new SecurityException(KLRes.UserAccountKeyError);
m_pbKeyData = new ProtectedBinary(true, pbKey);
Array.Clear(pbKey, 0, pbKey.Length);
throw new NotSupportedException("DataProtection not supported on MonoForAndroid!");
}
// public void Clear()
@@ -100,13 +91,7 @@ namespace KeePassLib.Keys
#if !KeePassLibSD
try
{
string strFilePath = GetUserKeyFilePath(false);
byte[] pbProtectedKey = File.ReadAllBytes(strFilePath);
pbKey = ProtectedData.Unprotect(pbProtectedKey, m_pbEntropy,
DataProtectionScope.CurrentUser);
Array.Clear(pbProtectedKey, 0, pbProtectedKey.Length);
throw new NotSupportedException("DataProtection not supported on MonoForAndroid!");
}
catch(Exception exLoad)
{
@@ -126,18 +111,7 @@ namespace KeePassLib.Keys
#if !KeePassLibSD
try
{
string strFilePath = GetUserKeyFilePath(true);
byte[] pbRandomKey = CryptoRandom.Instance.GetRandomBytes(64);
byte[] pbProtectedKey = ProtectedData.Protect(pbRandomKey,
m_pbEntropy, DataProtectionScope.CurrentUser);
File.WriteAllBytes(strFilePath, pbProtectedKey);
Array.Clear(pbProtectedKey, 0, pbProtectedKey.Length);
Array.Clear(pbRandomKey, 0, pbRandomKey.Length);
pbKey = LoadUserKey(true);
throw new NotSupportedException("DataProtection not supported on MonoForAndroid!");
}
catch(Exception) { pbKey = null; }
#endif

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -90,13 +92,14 @@ namespace KeePassLib.Native
m_platID = Environment.OSVersion.Platform;
#if !KeePassLibSD
// Mono returns PlatformID.Unix on Mac OS X, workaround this
/*// Mono returns PlatformID.Unix on Mac OS X, workaround this
//fails on Anroid
if(m_platID.Value == PlatformID.Unix)
{
if((RunConsoleApp("uname", null) ?? string.Empty).Trim().Equals(
"Darwin", StrUtil.CaseIgnoreCmp))
m_platID = PlatformID.MacOSX;
}
}*/
#endif
return m_platID.Value;

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,8 +26,10 @@ using System.IO;
using KeePassLib.Utility;
namespace KeePassLib
{
/// <summary>
/// Custom icon. <c>PwCustomIcon</c> objects are immutable.
/// </summary>
@@ -33,7 +37,7 @@ namespace KeePassLib
{
private PwUuid m_pwUuid;
private byte[] m_pbImageDataPng;
private Image m_pCachedImage;
private Android.Graphics.Bitmap m_pCachedImage;
public PwUuid Uuid
{
@@ -45,7 +49,7 @@ namespace KeePassLib
get { return m_pbImageDataPng; }
}
public Image Image
public Android.Graphics.Bitmap Image
{
get { return m_pCachedImage; }
}

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -1405,7 +1407,7 @@ namespace KeePassLib
/// </summary>
/// <param name="pwIconId">ID of the icon.</param>
/// <returns>Image data.</returns>
public Image GetCustomIcon(PwUuid pwIconId)
public Android.Graphics.Bitmap GetCustomIcon(PwUuid pwIconId)
{
int nIndex = GetCustomIconIndex(pwIconId);

View File

@@ -40,5 +40,5 @@ public class R {
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
to reference the layout/main.axml file, or R.strings.first_string to reference the first
to reference the layout/main.axml file, or R.Strings.first_string to reference the first
string in the dictionary file values/strings.xml.

View File

@@ -1,3 +1,4 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
@@ -8,10 +9,13 @@
// </auto-generated>
//------------------------------------------------------------------------------
[assembly: Android.Runtime.ResourceDesignerAttribute("KeePassLib2Android.Resource", IsApplication=false)]
namespace KeePassLib2Android
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("Novell.MonoDroid.Build.Tasks", "1.0.0.0")]
public partial class Resource
{
@@ -27,7 +31,7 @@ namespace KeePassLib2Android
{
// aapt resource value: 0x7f020000
public const int library_name = 2130837504;
public static int library_name = 2130837504;
private String()
{
@@ -35,3 +39,4 @@ namespace KeePassLib2Android
}
}
}
#pragma warning restore 1591

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -73,16 +75,8 @@ namespace KeePassLib.Security
static ProtectedBinary()
{
try // Test whether ProtectedMemory is supported
{
byte[] pbDummy = new byte[PmBlockSize * 2];
ProtectedMemory.Protect(pbDummy, MemoryProtectionScope.SameProcess);
m_bProtectionSupported = true;
}
catch(Exception) // Windows 98 / ME
{
m_bProtectionSupported = false;
}
//protection not supported on Android currently
m_bProtectionSupported = false;
}
/// <summary>
@@ -143,7 +137,7 @@ namespace KeePassLib.Security
// Data size must be > 0, otherwise 'Protect' throws
if(m_bProtected && m_bProtectionSupported && (m_uDataLen > 0))
ProtectedMemory.Protect(m_pbData, MemoryProtectionScope.SameProcess);
throw new NotSupportedException();
}
/// <summary>
@@ -164,9 +158,7 @@ namespace KeePassLib.Security
{
lock(m_objSync)
{
ProtectedMemory.Unprotect(m_pbData, MemoryProtectionScope.SameProcess);
Array.Copy(m_pbData, pbReturn, (int)m_uDataLen);
ProtectedMemory.Protect(m_pbData, MemoryProtectionScope.SameProcess);
throw new NotSupportedException();
}
}
else Array.Copy(m_pbData, pbReturn, (int)m_uDataLen);

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -137,7 +139,7 @@ namespace KeePassLib.Serialization
if(!v[0].StartsWith(LockFileHeader)) { Debug.Assert(false); return null; }
return new LockFileInfo(v[1], v[2], v[3], v[4], v[5]);
}
catch(FileNotFoundException) { }
catch(Java.IO.FileNotFoundException) { }
catch(Exception) { Debug.Assert(false); }
finally { if(s != null) s.Close(); }

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -92,7 +94,7 @@ namespace KeePassLib.Serialization
bool bMadeUnhidden = UrlUtil.UnhideFile(m_iocBase.Path);
#if !KeePassLibSD
FileSecurity bkSecurity = null;
bool bEfsEncrypted = false;
#endif
@@ -107,7 +109,7 @@ namespace KeePassLib.Serialization
bEfsEncrypted = ((long)(faBase & FileAttributes.Encrypted) != 0);
DateTime tCreation = File.GetCreationTime(m_iocBase.Path);
bkSecurity = File.GetAccessControl(m_iocBase.Path);
File.SetCreationTime(m_iocTemp.Path, tCreation);
}
@@ -131,8 +133,6 @@ namespace KeePassLib.Serialization
catch(Exception) { Debug.Assert(false); }
}
if(bkSecurity != null)
File.SetAccessControl(m_iocBase.Path, bkSecurity);
}
catch(Exception) { Debug.Assert(false); }
}

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -32,6 +34,44 @@ using KeePassLibSD;
namespace KeePassLib.Serialization
{
[System.Serializable]
public class InvalidDataException: Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="T:InvalidDataExceptionException"/> class
/// </summary>
public InvalidDataException ()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:InvalidDataExceptionException"/> class
/// </summary>
/// <param name="message">A <see cref="T:System.String"/> that describes the exception. </param>
public InvalidDataException (string message) : base (message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:InvalidDataExceptionException"/> class
/// </summary>
/// <param name="message">A <see cref="T:System.String"/> that describes the exception. </param>
/// <param name="inner">The exception that is the cause of the current exception. </param>
public InvalidDataException (string message, Exception inner) : base (message, inner)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:InvalidDataExceptionException"/> class
/// </summary>
/// <param name="context">The contextual information about the source or destination.</param>
/// <param name="info">The object that holds the serialized object data.</param>
protected InvalidDataException (System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base (info, context)
{
}
}
public sealed class HashedBlockStream : Stream
{
private const int m_nDefaultBufferSize = 1024 * 1024; // 1 MB

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -243,6 +245,41 @@ namespace KeePassLib.Serialization
}
#if !KeePassLibSD
class UploadOnCloseMemoryStream: MemoryStream
{
System.Net.WebClient webClient;
string method;
Uri destinationFilePath;
public UploadOnCloseMemoryStream(System.Net.WebClient _webClient, string _method, Uri _destinationFilePath)
{
this.webClient = _webClient;
this.method = _method;
this.destinationFilePath = _destinationFilePath;
}
public UploadOnCloseMemoryStream(System.Net.WebClient _webClient, Uri _destinationFilePath)
{
this.webClient = _webClient;
this.method = null;
this.destinationFilePath = _destinationFilePath;
}
public override void Close()
{
base.Close();
if (method != null)
{
webClient.UploadData(destinationFilePath, method, this.ToArray());
} else
{
webClient.UploadData(destinationFilePath, this.ToArray());
}
}
}
public static Stream OpenWrite(IOConnectionInfo ioc)
{
if(ioc == null) { Debug.Assert(false); return null; }
@@ -256,9 +293,9 @@ namespace KeePassLib.Serialization
if(NativeLib.IsUnix() && (uri.Scheme.Equals(Uri.UriSchemeHttp,
StrUtil.CaseIgnoreCmp) || uri.Scheme.Equals(Uri.UriSchemeHttps,
StrUtil.CaseIgnoreCmp)))
return CreateWebClient(ioc).OpenWrite(uri, WebRequestMethods.Http.Put);
return new UploadOnCloseMemoryStream(CreateWebClient(ioc), WebRequestMethods.Http.Put, uri);
return CreateWebClient(ioc).OpenWrite(uri);
return new UploadOnCloseMemoryStream(CreateWebClient(ioc), uri);
}
#else
public static Stream OpenWrite(IOConnectionInfo ioc)
@@ -296,7 +333,7 @@ namespace KeePassLib.Serialization
try
{
Stream s = OpenRead(ioc);
if(s == null) throw new FileNotFoundException();
if(s == null) throw new Java.IO.FileNotFoundException();
try { s.ReadByte(); }
catch(Exception) { }

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -43,6 +45,49 @@ namespace KeePassLib.Serialization
/// </summary>
public sealed partial class KdbxFile
{
private class ColorTranslator
{
public static Color FromHtml(String colorString)
{
Color color;
if (colorString.StartsWith("#"))
{
colorString = colorString.Substring(1);
}
if (colorString.EndsWith(";"))
{
colorString = colorString.Substring(0, colorString.Length - 1);
}
int red, green, blue;
switch (colorString.Length)
{
case 6:
red = int.Parse(colorString.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
green = int.Parse(colorString.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
blue = int.Parse(colorString.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
color = Color.FromArgb(red, green, blue);
break;
case 3:
red = int.Parse(colorString.Substring(0, 1), System.Globalization.NumberStyles.HexNumber);
green = int.Parse(colorString.Substring(1, 1), System.Globalization.NumberStyles.HexNumber);
blue = int.Parse(colorString.Substring(2, 1), System.Globalization.NumberStyles.HexNumber);
color = Color.FromArgb(red, green, blue);
break;
case 1:
red = green = blue = int.Parse(colorString.Substring(0, 1), System.Globalization.NumberStyles.HexNumber);
color = Color.FromArgb(red, green, blue);
break;
default:
throw new ArgumentException("Invalid color: " + colorString);
}
return color;
}
}
private enum KdbContext
{
Null,

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,7 +29,6 @@ using System.Security;
using System.Security.Cryptography;
using System.Drawing;
using System.Globalization;
using System.Drawing.Imaging;
#if !KeePassLibSD
using System.IO.Compression;

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,7 +23,6 @@ using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using System.Diagnostics;
using System.Xml.Serialization;
using System.Globalization;
@@ -33,8 +34,12 @@ using KeePassLib.Utility;
namespace KeePassLib.Translation
{
public class Control
{}
public sealed class KpccLayout
{
public enum LayoutParameterEx
{
X, Y, Width, Height
@@ -113,7 +118,7 @@ namespace KeePassLib.Translation
}
#if !KeePassLibSD
internal void ApplyTo(Control c)
/*internal void ApplyTo(Control c)
{
Debug.Assert(c != null); if(c == null) return;
@@ -181,7 +186,7 @@ namespace KeePassLib.Translation
Debug.Assert(false);
return null;
}
}*/
#endif
public static string ToControlRelativeString(string strEncoded)
@@ -268,7 +273,7 @@ namespace KeePassLib.Translation
}
#if !KeePassLibSD
private static readonly Type[] m_vTextControls = new Type[] {
/*private static readonly Type[] m_vTextControls = new Type[] {
typeof(MenuStrip), typeof(PictureBox), typeof(ListView),
typeof(TreeView), typeof(ToolStrip), typeof(WebBrowser),
typeof(Panel), typeof(StatusStrip), typeof(ProgressBar),
@@ -394,7 +399,7 @@ namespace KeePassLib.Translation
// Currently only v1: is supported, see HashControl
return (m_strHash == strHash);
}
}*/
#endif
}
}

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,13 +22,14 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.Diagnostics;
using System.Reflection;
namespace KeePassLib.Translation
{
public class Form
{}
public sealed class KPFormCustomization
{
private string m_strFQName = string.Empty;
@@ -75,7 +78,7 @@ namespace KeePassLib.Translation
}
#if !KeePassLibSD
public void ApplyTo(Form form)
/*public void ApplyTo(Form form)
{
Debug.Assert(form != null); if(form == null) throw new ArgumentNullException("form");
@@ -100,7 +103,7 @@ namespace KeePassLib.Translation
}
foreach(Control cSub in c.Controls) ApplyToControl(cSub);
}
}*/
#endif
}
}

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,11 +23,13 @@ using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.Windows.Forms;
using System.Diagnostics;
namespace KeePassLib.Translation
{
public class ToolStripItemCollection
{}
public sealed class KPStringTable
{
private string m_strName = string.Empty;
@@ -67,7 +71,7 @@ namespace KeePassLib.Translation
}
#if !KeePassLibSD
public void ApplyTo(ToolStripItemCollection tsic)
/*public void ApplyTo(ToolStripItemCollection tsic)
{
if(tsic == null) throw new ArgumentNullException("tsic");
@@ -93,7 +97,7 @@ namespace KeePassLib.Translation
if((tsmi != null) && (tsmi.DropDownItems != null))
this.ApplyTo(tsmi.DropDownItems);
}
}
}*/
#endif
}
}

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,7 +25,7 @@ using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;
using System.Diagnostics;
@@ -154,7 +156,7 @@ namespace KeePassLib.Translation
}
#if !KeePassLibSD
public void ApplyTo(Form form)
/*public void ApplyTo(Form form)
{
if(form == null) throw new ArgumentNullException("form");
@@ -183,8 +185,8 @@ namespace KeePassLib.Translation
try { RtlApplyToControls(form.Controls); }
catch(Exception) { Debug.Assert(false); }
}
}
}*/
/*
private static void RtlApplyToControls(Control.ControlCollection cc)
{
foreach(Control c in cc)
@@ -210,9 +212,9 @@ namespace KeePassLib.Translation
if((c is GroupBox) || (c is Panel)) RtlMoveChildControls(c);
}
}
}*/
private static void RtlMoveChildControls(Control cParent)
/*private static void RtlMoveChildControls(Control cParent)
{
int nParentWidth = cParent.Size.Width;
@@ -246,7 +248,7 @@ namespace KeePassLib.Translation
}
if(kpst != null) kpst.ApplyTo(tsic);
}
}*/
#endif
}
}

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,14 +24,15 @@ using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
using Android.Graphics;
namespace KeePassLib.Utility
{
public static class GfxUtil
{
public static Image LoadImage(byte[] pb)
public static Android.Graphics.Bitmap LoadImage(byte[] pb)
{
if(pb == null) throw new ArgumentNullException("pb");
@@ -37,59 +40,43 @@ namespace KeePassLib.Utility
try { return LoadImagePriv(ms); }
catch(Exception)
{
Image imgIco = TryLoadIco(pb);
Android.Graphics.Bitmap imgIco = TryLoadIco(pb);
if(imgIco != null) return imgIco;
throw;
}
finally { ms.Close(); }
}
private static Image LoadImagePriv(Stream s)
private static Android.Graphics.Bitmap LoadImagePriv(Stream s)
{
// Image.FromStream wants the stream to be open during
// the whole lifetime of the image; as we can't guarantee
// this, we make a copy of the image
Image imgSrc = null;
try
{
#if !KeePassLibSD
imgSrc = Image.FromStream(s);
Bitmap bmp = new Bitmap(imgSrc.Width, imgSrc.Height,
PixelFormat.Format32bppArgb);
Android.Graphics.Bitmap img = null;
#if !KeePassLibSD
img = BitmapFactory.DecodeStream(s);
try
{
bmp.SetResolution(imgSrc.HorizontalResolution,
imgSrc.VerticalResolution);
Debug.Assert(bmp.Size == imgSrc.Size);
}
catch(Exception) { Debug.Assert(false); }
#else
imgSrc = new Bitmap(s);
Bitmap bmp = new Bitmap(imgSrc.Width, imgSrc.Height);
#endif
using(Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.Transparent);
g.DrawImage(imgSrc, 0, 0);
}
return bmp;
}
finally { if(imgSrc != null) imgSrc.Dispose(); }
return img;
}
private static Image TryLoadIco(byte[] pb)
private static Android.Graphics.Bitmap TryLoadIco(byte[] pb)
{
#if !KeePassLibSD
throw new NotImplementedException();
/*
MemoryStream ms = new MemoryStream(pb, false);
try { return (new Icon(ms)).ToBitmap(); }
catch(Exception) { }
finally { ms.Close(); }
finally { ms.Close(); }*/
#endif
return null;
//return null;
}
}
}

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,7 +23,7 @@ using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using KeePassLib.Resources;
@@ -29,17 +31,36 @@ using KeePassLib.Serialization;
namespace KeePassLib.Utility
{
public enum MessageBoxButtons
{
OK, OKCancel, AbortRetryIgnore, YesNoCancel, YesNo, RetryCancel
}
public enum MessageBoxIcon
{
Information, Warning, Error, Question
}
public enum MessageBoxDefaultButton
{
Button1, Button2, Button3
}
public enum DialogResult
{
Yes, No, Cancel, Retry, Abort
}
public sealed class MessageServiceEventArgs : EventArgs
{
private string m_strTitle = string.Empty;
private string m_strText = string.Empty;
private MessageBoxButtons m_msgButtons = MessageBoxButtons.OK;
private MessageBoxIcon m_msgIcon = MessageBoxIcon.None;
//private MessageBoxButtons m_msgButtons = MessageBoxButtons.OK;
//private MessageBoxIcon m_msgIcon = MessageBoxIcon.None;
public string Title { get { return m_strTitle; } }
public string Text { get { return m_strText; } }
public MessageBoxButtons Buttons { get { return m_msgButtons; } }
public MessageBoxIcon Icon { get { return m_msgIcon; } }
//public MessageBoxButtons Buttons { get { return m_msgButtons; } }
//public MessageBoxIcon Icon { get { return m_msgIcon; } }
public MessageServiceEventArgs() { }
@@ -48,8 +69,7 @@ namespace KeePassLib.Utility
{
m_strTitle = (strTitle ?? string.Empty);
m_strText = (strText ?? string.Empty);
m_msgButtons = msgButtons;
m_msgIcon = msgIcon;
}
}
@@ -62,14 +82,12 @@ namespace KeePassLib.Utility
private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Warning;
private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Error;
private const MessageBoxOptions m_mboRtl = (MessageBoxOptions.RtlReading |
MessageBoxOptions.RightAlign);
#else
private const MessageBoxIcon m_mbiInfo = MessageBoxIcon.Asterisk;
private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Exclamation;
private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Hand;
#endif
private const MessageBoxIcon m_mbiQuestion = MessageBoxIcon.Question;
//private const MessageBoxIcon m_mbiQuestion = MessageBoxIcon.Question;
public static string NewLine
{
@@ -159,13 +177,13 @@ namespace KeePassLib.Utility
}
#if !KeePassLibSD
internal static Form GetTopForm()
/*internal static Form GetTopForm()
{
FormCollection fc = Application.OpenForms;
if((fc == null) || (fc.Count == 0)) return null;
return fc[fc.Count - 1];
}
}*/
#endif
private static DialogResult SafeShowMessageBox(string strText, string strTitle,
@@ -174,7 +192,14 @@ namespace KeePassLib.Utility
#if KeePassLibSD
return MessageBox.Show(strText, strTitle, mb, mi, mdb);
#else
IWin32Window wnd = null;
if (mb == MessageBoxButtons.OK)
{
//Android.Widget.Toast toast = ..
}
//this might help: http://www.gregshackles.com/2011/04/using-background-threads-in-mono-for-android-applications/
throw new NotImplementedException();
/*IWin32Window wnd = null;
try
{
Form f = GetTopForm();
@@ -203,11 +228,12 @@ namespace KeePassLib.Utility
if(StrUtil.RightToLeft)
return MessageBox.Show(strText, strTitle, mb, mi, mdb, m_mboRtl);
return MessageBox.Show(strText, strTitle, mb, mi, mdb);
*/
#endif
}
#if !KeePassLibSD
internal delegate DialogResult SafeShowMessageBoxInternalDelegate(IWin32Window iParent,
/* internal delegate DialogResult SafeShowMessageBoxInternalDelegate(IWin32Window iParent,
string strText, string strTitle, MessageBoxButtons mb, MessageBoxIcon mi,
MessageBoxDefaultButton mdb);
@@ -218,7 +244,7 @@ namespace KeePassLib.Utility
if(StrUtil.RightToLeft)
return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb, m_mboRtl);
return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb);
}
}*/
#endif
public static void ShowInfo(params object[] vLines)
@@ -284,8 +310,9 @@ namespace KeePassLib.Utility
try
{
#if !KeePassLibSD
Clipboard.Clear();
Clipboard.SetText(ObjectsToMessage(vLines, true));
/* nicht benoetigt - hoffentlich :-)
Clipboard.Clear();
Clipboard.SetText(ObjectsToMessage(vLines, true));*/
#else
Clipboard.SetDataObject(ObjectsToMessage(vLines, true));
#endif
@@ -312,10 +339,10 @@ namespace KeePassLib.Utility
if(MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitleEx, strTextEx, mbb, m_mbiQuestion));
strTitleEx, strTextEx, mbb, MessageBoxIcon.Question));
DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx, mbb,
m_mbiQuestion, MessageBoxDefaultButton.Button1);
MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
--m_uCurrentMessageCount;
return dr;
@@ -330,10 +357,10 @@ namespace KeePassLib.Utility
if(MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitleEx, strTextEx, MessageBoxButtons.YesNo, m_mbiQuestion));
strTitleEx, strTextEx, MessageBoxButtons.YesNo, MessageBoxIcon.Question));
DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx,
MessageBoxButtons.YesNo, m_mbiQuestion, bDefaultToYes ?
MessageBoxButtons.YesNo, MessageBoxIcon.Question, bDefaultToYes ?
MessageBoxDefaultButton.Button1 : MessageBoxDefaultButton.Button2);
--m_uCurrentMessageCount;

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -990,15 +992,7 @@ namespace KeePassLib.Utility
try
{
byte[] pbPlain = StrUtil.Utf8.GetBytes(strPlainText);
byte[] pbEnc = ProtectedData.Protect(pbPlain, m_pbOptEnt,
DataProtectionScope.CurrentUser);
#if !KeePassLibSD
return Convert.ToBase64String(pbEnc, Base64FormattingOptions.None);
#else
return Convert.ToBase64String(pbEnc);
#endif
throw new NotSupportedException();
}
catch(Exception) { Debug.Assert(false); }
@@ -1012,10 +1006,8 @@ namespace KeePassLib.Utility
try
{
byte[] pbEnc = Convert.FromBase64String(strCipherText);
byte[] pbPlain = ProtectedData.Unprotect(pbEnc, m_pbOptEnt,
DataProtectionScope.CurrentUser);
throw new NotSupportedException();
return StrUtil.Utf8.GetString(pbPlain, 0, pbPlain.Length);
}
catch(Exception) { Debug.Assert(false); }

View File

@@ -0,0 +1,72 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Content.PM;
namespace keepass2android
{
public class AboutDialog : Dialog {
public AboutDialog(Context context):base (context) {
}
protected override void OnCreate(Bundle savedInstanceState) {
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.about);
SetTitle(Resource.String.app_name);
setVersion();
Button okButton = (Button) FindViewById(Resource.Id.about_button);
okButton.Click += (object sender, EventArgs e) => {
Dismiss();
};
}
private void setVersion() {
Context ctx = Context;
String version;
try {
PackageInfo packageInfo = ctx.PackageManager.GetPackageInfo(ctx.PackageName, 0);
version = packageInfo.VersionName;
} catch (PackageManager.NameNotFoundException) {
version = "";
}
TextView tv = (TextView) FindViewById(Resource.Id.version);
tv.Text = version;
}
}
}

View File

@@ -0,0 +1,20 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using Android.App;

View File

@@ -0,0 +1,45 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Graphics.Drawables;
using Android.Content.Res;
using Android.Graphics;
namespace keepass2android
{
public class BitmapDrawableCompat {
public static BitmapDrawable getBitmapDrawable(Resources res, Bitmap bitmap) {
return new BitmapDrawable(res, bitmap);
}
}
}

View File

@@ -0,0 +1,52 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace keepass2android
{
public class CancelDialog : Dialog {
private bool mCanceled = false;
public CancelDialog(Context context): base(context) {
}
public bool canceled() {
return mCanceled;
}
public override void Cancel() {
base.Cancel();
mCanceled = true;
}
}
}

View File

@@ -0,0 +1,244 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using KeePassLib;
using KeePassLib.Interfaces;
using KeePassLib.Serialization;
namespace keepass2android
{
public class Database {
public Dictionary<PwUuid, PwGroup> groups = new Dictionary<PwUuid, PwGroup>(new PwUuidEqualityComparer());
public Dictionary<PwUuid, PwEntry> entries = new Dictionary<PwUuid, PwEntry>(new PwUuidEqualityComparer());
public HashSet<PwGroup> dirty = new HashSet<PwGroup>(new PwGroupEqualityFromIdComparer());
public PwGroup root;
public PwDatabase pm;
public IOConnectionInfo mIoc;
public SearchDbHelper searchHelper;
public DrawableFactory drawFactory = new DrawableFactory();
private bool loaded = false;
public bool Loaded {
get { return loaded;}
set { loaded = value; }
}
public bool Open
{
get { return Loaded && (!Locked); }
}
bool locked;
public bool Locked
{
get
{
return locked;
}
set
{
locked = value;
}
}
public void LoadData (Context ctx, IOConnectionInfo iocInfo, String password, String keyfile, UpdateStatus status)
{
mIoc = iocInfo;
KeePassLib.PwDatabase pwDatabase = new KeePassLib.PwDatabase ();
KeePassLib.Keys.CompositeKey key = new KeePassLib.Keys.CompositeKey ();
key.AddUserKey (new KeePassLib.Keys.KcpPassword (password));
if (!String.IsNullOrEmpty (keyfile)) {
try { key.AddUserKey(new KeePassLib.Keys.KcpKeyFile(keyfile)); }
catch(Exception)
{
throw new KeyFileException();
}
}
pwDatabase.Open(iocInfo, key, status);
root = pwDatabase.RootGroup;
populateGlobals(root);
Loaded = true;
pm = pwDatabase;
searchHelper = new SearchDbHelper(ctx);
}
bool quickUnlockEnabled = false;
public bool QuickUnlockEnabled
{
get
{
return quickUnlockEnabled;
}
set
{
quickUnlockEnabled = value;
}
}
//KeyLength of QuickUnlock at time of loading the database.
//This is important to not allow an attacker to set the length to 1 when QuickUnlock is started already.
public int QuickUnlockKeyLength
{
get;
set;
}
public PwGroup SearchForText(String str) {
PwGroup group = searchHelper.searchForText(this, str);
return group;
}
public PwGroup Search(SearchParameters searchParams)
{
return searchHelper.search(this, searchParams);
}
public PwGroup SearchForExactUrl(String url) {
PwGroup group = searchHelper.searchForExactUrl(this, url);
return group;
}
public PwGroup SearchForHost(String url) {
PwGroup group = searchHelper.searchForHost(this, url);
return group;
}
public void SaveData(Context ctx) {
ISharedPreferences prefs = Android.Preferences.PreferenceManager.GetDefaultSharedPreferences(ctx);
pm.UseFileTransactions = prefs.GetBoolean(ctx.GetString(Resource.String.UseFileTransactions_key), true);
pm.Save(null);
}
class SaveStatusLogger: IStatusLogger
{
#region IStatusLogger implementation
public void StartLogging (string strOperation, bool bWriteOperationToLog)
{
}
public void EndLogging ()
{
}
public bool SetProgress (uint uPercent)
{
Android.Util.Log.Debug("DEBUG", "Progress: " + uPercent+"%");
return true;
}
public bool SetText (string strNewText, LogStatusType lsType)
{
Android.Util.Log.Debug("DEBUG", strNewText);
return true;
}
public bool ContinueWork ()
{
return true;
}
#endregion
}
private void populateGlobals (PwGroup currentGroup)
{
var childGroups = currentGroup.Groups;
var childEntries = currentGroup.Entries;
foreach (PwEntry e in childEntries) {
entries [e.Uuid] = e;
}
foreach (PwGroup g in childGroups) {
groups[g.Uuid] = g;
populateGlobals(g);
}
}
public void Clear() {
groups.Clear();
entries.Clear();
dirty.Clear();
drawFactory.Clear();
root = null;
pm = null;
mIoc = null;
loaded = false;
locked = false;
}
public void markAllGroupsAsDirty() {
foreach ( PwGroup group in groups.Values ) {
dirty.Add(group);
}
}
}
/*
public void LoadData (Context mCtx, string mFileName, string mPass, string mKey, UpdateStatus mStatus)
{
KeePassLib.PwDatabase pwDatabase = new KeePassLib.PwDatabase();
KeePassLib.Serialization.IOConnectionInfo iocInfo = KeePassLib.Serialization.IOConnectionInfo.FromPath("/sdcard/keepass2androidtest.kdbx");
KeePassLib.Serialization.IOConnectionInfo iocInfoSave = KeePassLib.Serialization.IOConnectionInfo.FromPath("/sdcard/keepass2androidtestSaved.kdbx");
KeePassLib.Keys.CompositeKey key = new KeePassLib.Keys.CompositeKey();
key.AddUserKey(new KeePassLib.Keys.KcpPassword("test"));
pwDatabase.Open(iocInfo, key, new LogToButton(this));
pwDatabase.RootGroup.AddGroup(new KeePassLib.PwGroup(true, true, "generatedFromKp2ANeu", KeePassLib.PwIcon.Folder), true);
pwDatabase.SaveAs(iocInfoSave,false,new LogToButton(this));
pwDatabase.Close();
//KeePassLib.Serialization.KdbxFile f = new KeePassLib.Serialization.KdbxFile(pwDatabase);
}
*/
}

View File

@@ -0,0 +1,519 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using KeePassLib;
using Android.Text.Format;
using KeePassLib.Utility;
using Java.Util;
using Android.Preferences;
using Android.Text.Method;
using Android.Util;
using System.Globalization;
using Android.Content.PM;
using KeePassLib.Security;
using keepass2android.view;
using Android.Webkit;
namespace keepass2android
{
[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden, Theme="@style/NoTitleBar")]
public class EntryActivity : LockCloseActivity {
public const String KEY_ENTRY = "entry";
public const String KEY_REFRESH_POS = "refresh_pos";
public const String KEY_CLOSE_AFTER_CREATE = "close_after_create";
public static void Launch(Activity act, PwEntry pw, int pos) {
Launch(act, pw, pos, false);
}
public static void Launch(Activity act, PwEntry pw, int pos, bool closeAfterCreate) {
Intent i;
i = new Intent(act, typeof(EntryActivity));
i.PutExtra(KEY_ENTRY, pw.Uuid.ToHexString());
i.PutExtra(KEY_REFRESH_POS, pos);
i.PutExtra(KEY_CLOSE_AFTER_CREATE, closeAfterCreate);
act.StartActivityForResult(i,0);
}
protected PwEntry mEntry;
private bool mShowPassword;
private int mPos;
protected void setEntryView() {
SetContentView(Resource.Layout.entry_view);
}
protected void setupEditButtons() {
Button edit = (Button) FindViewById(Resource.Id.entry_edit);
edit.Click += (sender, e) => {
EntryEditActivity.Launch(this, mEntry);
};
}
protected override void OnCreate(Bundle savedInstanceState)
{
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
mShowPassword = ! prefs.GetBoolean(GetString(Resource.String.maskpass_key), Resources.GetBoolean(Resource.Boolean.maskpass_default));
base.OnCreate(savedInstanceState);
setEntryView();
Context appCtx = ApplicationContext;
Database db = App.getDB();
// Likely the app has been killed exit the activity
if (! db.Loaded)
{
Finish();
return;
}
SetResult(KeePass.EXIT_NORMAL);
Intent i = Intent;
PwUuid uuid = new PwUuid(MemUtil.HexStringToByteArray(i.GetStringExtra(KEY_ENTRY)));
mPos = i.GetIntExtra(KEY_REFRESH_POS, -1);
bool closeAfterCreate = i.GetBooleanExtra(KEY_CLOSE_AFTER_CREATE, false);
mEntry = db.entries [uuid];
// Refresh Menu contents in case onCreateMenuOptions was called before mEntry was set
ActivityCompat.invalidateOptionsMenu(this);
// Update last access time.
mEntry.Touch(false);
if (PwDefs.IsTanEntry(mEntry) && prefs.GetBoolean(GetString(Resource.String.TanExpiresOnUse_key), Resources.GetBoolean(Resource.Boolean.TanExpiresOnUse_default)) && ((mEntry.Expires == false) || mEntry.ExpiryTime > DateTime.Now))
{
PwEntry backupEntry = mEntry.CloneDeep();
mEntry.ExpiryTime = DateTime.Now;
mEntry.Expires = true;
mEntry.Touch(true);
requiresRefresh();
Handler handler = new Handler();
UpdateEntry update = new UpdateEntry(this, App.getDB(), backupEntry, mEntry, new AfterSave(handler));
ProgressTask pt = new ProgressTask(this, update, Resource.String.saving_database);
pt.run();
}
fillData(false);
setupEditButtons();
Intent showNotIntent = new Intent(this, typeof(CopyToClipboardService));
Intent.SetAction(Intents.SHOW_NOTIFICATION);
showNotIntent.PutExtra(KEY_ENTRY, mEntry.Uuid.ToHexString());
StartService(showNotIntent);
Android.Util.Log.Debug("DEBUG", "Requesting copy to clipboard for Uuid=" + mEntry.Uuid.ToHexString());
/*foreach (PwUuid key in App.getDB().entries.Keys)
{
Android.Util.Log.Debug("DEBUG",key.ToHexString() + " -> " + App.getDB().entries[key].Uuid.ToHexString());
}*/
if (closeAfterCreate)
{
Finish();
}
}
private class AfterSave : OnFinish {
public AfterSave(Handler handler):base(handler) {
}
public override void run() {
base.run();
}
};
private String getDateTime(System.DateTime dt) {
return dt.ToString ("g", CultureInfo.CurrentUICulture);
}
String concatTags(List<string> tags)
{
StringBuilder sb = new StringBuilder();
foreach (string tag in tags)
{
sb.Append(tag);
sb.Append(", ");
}
if (tags.Count > 0)
sb.Remove(sb.Length-2,2);
return sb.ToString();
}
void populateExtraStrings(bool trimList)
{
ViewGroup extraGroup = (ViewGroup)FindViewById(Resource.Id.extra_strings);
if (trimList)
{
extraGroup.RemoveAllViews();
}
bool hasExtraFields = false;
foreach (KeyValuePair<string, ProtectedString> pair in mEntry.Strings)
{
String key = pair.Key;
if (!PwDefs.IsStandardField(key))
{
View view = new EntrySection(this, null, key, pair.Value.ReadString());
extraGroup.AddView(view);
hasExtraFields = true;
}
}
FindViewById(Resource.Id.entry_extra_strings_label).Visibility = hasExtraFields ? ViewStates.Visible : ViewStates.Gone;
}
string writeBinaryToFile(string key)
{
ProtectedBinary pb = mEntry.Binaries.Get(key);
System.Diagnostics.Debug.Assert(pb != null); if(pb == null) throw new ArgumentException();
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
string binaryDirectory = prefs.GetString(GetString(Resource.String.BinaryDirectory_key),GetString(Resource.String.BinaryDirectory_default));
var targetFile = new Java.IO.File(binaryDirectory,key);
Java.IO.File parent = targetFile.ParentFile;
if (parent == null || (parent.Exists() && ! parent.IsDirectory))
{
Toast.MakeText(this,
Resource.String.error_invalid_path,
ToastLength.Long).Show();
return null;
}
if (! parent.Exists())
{
// Create parent dircetory
if (! parent.Mkdirs())
{
Toast.MakeText(this,
Resource.String.error_could_not_create_parent,
ToastLength.Long).Show();
return null;
}
}
string filename = targetFile.AbsolutePath;
byte[] pbData = pb.ReadData();
try { System.IO.File.WriteAllBytes(filename, pbData); }
catch(Exception exWrite)
{
Toast.MakeText(this, GetString(Resource.String.SaveAttachment_Failed, new Java.Lang.Object[]{ filename})
+exWrite.Message,ToastLength.Long).Show();
return null;
}
finally
{
MemUtil.ZeroByteArray(pbData);
}
return filename;
}
void openBinaryFile(string filename)
{
String theMIMEType = getMimeType(filename);
if (theMIMEType != null)
{
Intent theIntent = new Intent(Intent.ActionView);
theIntent.AddFlags(ActivityFlags.NewTask | ActivityFlags.ExcludeFromRecents);
theIntent.SetDataAndType(Android.Net.Uri.FromFile(new Java.IO.File(filename)), theMIMEType);
try
{
StartActivity(theIntent);
}
catch (ActivityNotFoundException anfe)
{
//ignore
Toast.MakeText(this, "Couldn't open file", ToastLength.Short).Show();
}
}
}
void populateBinaries(bool trimList)
{
ViewGroup binariesGroup = (ViewGroup)FindViewById(Resource.Id.binaries);
if (trimList)
{
binariesGroup.RemoveAllViews();
}
foreach (KeyValuePair<string, ProtectedBinary> pair in mEntry.Binaries)
{
String key = pair.Key;
Button binaryButton = new Button(this);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FillParent, RelativeLayout.LayoutParams.WrapContent);
binaryButton.Text = key;
binaryButton.SetCompoundDrawablesWithIntrinsicBounds( Resources.GetDrawable(Android.Resource.Drawable.IcMenuSave),null, null, null);
binaryButton.Click += (object sender, EventArgs e) =>
{
Button btnSender = (Button)(sender);
string newFilename = writeBinaryToFile(btnSender.Text);
if (newFilename != null)
{
Toast.MakeText(this, GetString(Resource.String.SaveAttachment_doneMessage, new Java.Lang.Object[]{newFilename}), ToastLength.Short).Show();
openBinaryFile(newFilename);
}
};
binariesGroup.AddView(binaryButton,layoutParams);
}
FindViewById(Resource.Id.entry_binaries_label).Visibility = mEntry.Binaries.UCount > 0 ? ViewStates.Visible : ViewStates.Gone;
}
// url = file path or whatever suitable URL you want.
public static String getMimeType(String url)
{
String type = null;
String extension = MimeTypeMap.GetFileExtensionFromUrl(url);
if (extension != null) {
MimeTypeMap mime = MimeTypeMap.Singleton;
type = mime.GetMimeTypeFromExtension(extension);
}
return type;
}
protected void fillData(bool trimList)
{
ImageView iv = (ImageView)FindViewById(Resource.Id.entry_icon);
App.getDB().drawFactory.assignDrawableTo(iv, Resources, App.getDB().pm, mEntry.IconId, mEntry.CustomIconUuid);
//populateText(Resource.Id.entry_title, mEntry.Strings.ReadSafe(PwDefs.TitleField));
var button = ((Button)FindViewById(Resource.Id.entry_title));
button.Text = mEntry.Strings.ReadSafe(PwDefs.TitleField);
button.Click += (object sender, EventArgs e) => {
Finish(); };
populateText(Resource.Id.entry_user_name, Resource.Id.entry_user_name_label, mEntry.Strings.ReadSafe(PwDefs.UserNameField));
populateText(Resource.Id.entry_url, Resource.Id.entry_url_label, mEntry.Strings.ReadSafe(PwDefs.UrlField));
populateText(Resource.Id.entry_password, Resource.Id.entry_password_label, mEntry.Strings.ReadSafe(PwDefs.PasswordField));
setPasswordStyle();
populateText(Resource.Id.entry_created, Resource.Id.entry_created_label, getDateTime(mEntry.CreationTime));
populateText(Resource.Id.entry_modified, Resource.Id.entry_modified_label, getDateTime(mEntry.LastModificationTime));
populateText(Resource.Id.entry_accessed, Resource.Id.entry_accessed_label, getDateTime(mEntry.LastAccessTime));
if (mEntry.Expires)
{
populateText(Resource.Id.entry_expires, Resource.Id.entry_expires_label, getDateTime(mEntry.ExpiryTime));
} else
{
populateText(Resource.Id.entry_expires, Resource.Id.entry_expires_label, Resource.String.never);
}
populateText(Resource.Id.entry_comment, Resource.Id.entry_comment_label, mEntry.Strings.ReadSafe(PwDefs.NotesField));
populateText(Resource.Id.entry_tags, Resource.Id.entry_tags_label, concatTags(mEntry.Tags));
populateText(Resource.Id.entry_override_url, Resource.Id.entry_override_url_label, mEntry.OverrideUrl);
populateExtraStrings(trimList);
populateBinaries(trimList);
}
private void populateText(int viewId, int headerViewId,int resId) {
View header = FindViewById(headerViewId);
TextView tv = (TextView)FindViewById(viewId);
header.Visibility = tv.Visibility = ViewStates.Visible;
tv.SetText (resId);
}
private void populateText(int viewId, int headerViewId, String text)
{
View header = FindViewById(headerViewId);
TextView tv = (TextView)FindViewById(viewId);
if (String.IsNullOrEmpty(text))
{
header.Visibility = tv.Visibility = ViewStates.Gone;
}
else
{
header.Visibility = tv.Visibility = ViewStates.Visible;
tv.Text = text;
}
}
void requiresRefresh ()
{
Intent ret = new Intent ();
ret.PutExtra (KEY_REFRESH_POS, mPos);
SetResult (KeePass.EXIT_REFRESH, ret);
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) {
base.OnActivityResult(requestCode, resultCode, data);
if ( resultCode == KeePass.EXIT_REFRESH || resultCode == KeePass.EXIT_REFRESH_TITLE ) {
fillData(true);
if ( resultCode == KeePass.EXIT_REFRESH_TITLE ) {
requiresRefresh ();
}
}
}
public override bool OnCreateOptionsMenu(IMenu menu) {
base.OnCreateOptionsMenu(menu);
MenuInflater inflater = MenuInflater;
inflater.Inflate(Resource.Menu.entry, menu);
IMenuItem togglePassword = menu.FindItem(Resource.Id.menu_toggle_pass);
if ( mShowPassword ) {
togglePassword.SetTitle(Resource.String.menu_hide_password);
} else {
togglePassword.SetTitle(Resource.String.show_password);
}
IMenuItem gotoUrl = menu.FindItem(Resource.Id.menu_goto_url);
//Disabled IMenuItem copyUser = menu.FindItem(Resource.Id.menu_copy_user);
//Disabled IMenuItem copyPass = menu.FindItem(Resource.Id.menu_copy_pass);
// In API >= 11 onCreateOptionsMenu may be called before onCreate completes
// so mEntry may not be set
if (mEntry == null) {
gotoUrl.SetVisible(false);
//Disabled copyUser.SetVisible(false);
//Disabled copyPass.SetVisible(false);
}
else {
String url = mEntry.Strings.ReadSafe (PwDefs.UrlField);
if (String.IsNullOrEmpty(url)) {
// disable button if url is not available
gotoUrl.SetVisible(false);
}
if ( String.IsNullOrEmpty(mEntry.Strings.ReadSafe(PwDefs.UserNameField ))) {
// disable button if username is not available
//Disabled copyUser.SetVisible(false);
}
if ( String.IsNullOrEmpty(mEntry.Strings.ReadSafe(PwDefs.PasswordField ))) {
// disable button if password is not available
//Disabled copyPass.SetVisible(false);
}
}
return true;
}
private void setPasswordStyle() {
TextView password = (TextView) FindViewById(Resource.Id.entry_password);
if ( mShowPassword ) {
password.TransformationMethod = null;
} else {
password.TransformationMethod = PasswordTransformationMethod.Instance;
}
}
public override bool OnOptionsItemSelected(IMenuItem item) {
switch ( item.ItemId ) {
/*case Resource.Id.menu_donate:
try {
Util.gotoUrl(this, Resource.String.donate_url);
} catch (ActivityNotFoundException) {
Toast.MakeText(this, Resource.String.error_failed_to_launch_link, ToastLength.Long).Show();
return false;
}
return true;*/
case Resource.Id.menu_toggle_pass:
if ( mShowPassword ) {
item.SetTitle(Resource.String.show_password);
mShowPassword = false;
} else {
item.SetTitle(Resource.String.menu_hide_password);
mShowPassword = true;
}
setPasswordStyle();
return true;
case Resource.Id.menu_goto_url:
String url;
url = mEntry.Strings.ReadSafe (PwDefs.UserNameField);
// Default http:// if no protocol specified
if ( ! url.Contains("://") ) {
url = "http://" + url;
}
try {
Util.gotoUrl(this, url);
} catch (ActivityNotFoundException) {
Toast.MakeText(this, Resource.String.no_url_handler, ToastLength.Long).Show();
}
return true;
/* TODO: required?
case Resource.Id.menu_copy_user:
timeoutCopyToClipboard(mEntry.Strings.ReadSafe (PwDefs.UserNameField));
return true;
case Resource.Id.menu_copy_pass:
timeoutCopyToClipboard(mEntry.Strings.ReadSafe (PwDefs.UserNameField));
return true;
*/
case Resource.Id.menu_lock:
App.setShutdown();
SetResult(KeePass.EXIT_LOCK);
Finish();
return true;
}
return base.OnOptionsItemSelected(item);
}
}
}

View File

@@ -0,0 +1,739 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Preferences;
using KeePassLib.Utility;
using KeePassLib;
using Android.Text;
using KeePassLib.Security;
using Android.Content.PM;
using keepass2android.view;
using System.IO;
using System.Globalization;
namespace keepass2android
{
[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden, Theme="@style/NoTitleBar")]
public class EntryEditActivity : LockCloseActivity {
public const String KEY_ENTRY = "entry";
public const String KEY_PARENT = "parent";
public const int RESULT_OK_ICON_PICKER = (int)Result.FirstUser + 1000;
public const int RESULT_OK_PASSWORD_GENERATOR = RESULT_OK_ICON_PICKER + 1;
private PwEntry mEntry, mEntryInDatabase;
private bool mShowPassword = false;
private bool mIsNew;
private PwIcon mSelectedIconID;
private PwUuid mSelectedCustomIconID = PwUuid.Zero;
private bool mSelectedIcon = false;
public static void Launch(Activity act, PwEntry pw) {
Intent i = new Intent(act, typeof(EntryEditActivity));
i.PutExtra(KEY_ENTRY, pw.Uuid.ToHexString());
act.StartActivityForResult(i, 0);
}
public static void Launch(Activity act, PwGroup pw) {
Intent i = new Intent(act, typeof(EntryEditActivity));
PwGroup parent = pw;
i.PutExtra(KEY_PARENT, parent.Uuid.ToHexString());
act.StartActivityForResult(i, 0);
}
private ScrollView scroll;
protected override void OnCreate(Bundle savedInstanceState)
{
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
mShowPassword = ! prefs.GetBoolean(GetString(Resource.String.maskpass_key), Resources.GetBoolean(Resource.Boolean.maskpass_default));
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.entry_edit);
SetResult(KeePass.EXIT_NORMAL);
// Likely the app has been killed exit the activity
Database db = App.getDB();
if ( ! db.Open ) {
Finish();
return;
}
Intent i = Intent;
String uuidBytes = i.GetStringExtra(KEY_ENTRY);
PwUuid entryId = PwUuid.Zero;
if (uuidBytes != null)
entryId = new KeePassLib.PwUuid(MemUtil.HexStringToByteArray(uuidBytes));
PwGroup parentGroup = null;
if ( entryId == PwUuid.Zero ) {
String groupId = i.GetStringExtra(KEY_PARENT);
parentGroup = db.groups[new PwUuid(MemUtil.HexStringToByteArray(groupId))];
mEntryInDatabase = new PwEntry(true, true);
mEntryInDatabase.Strings.Set(PwDefs.UserNameField, new ProtectedString(
db.pm.MemoryProtection.ProtectUserName, db.pm.DefaultUserName));
/*KPDesktop
* ProtectedString psAutoGen;
PwGenerator.Generate(out psAutoGen, Program.Config.PasswordGenerator.AutoGeneratedPasswordsProfile,
null, Program.PwGeneratorPool);
psAutoGen = psAutoGen.WithProtection(pwDb.MemoryProtection.ProtectPassword);
pwe.Strings.Set(PwDefs.PasswordField, psAutoGen);
int nExpireDays = Program.Config.Defaults.NewEntryExpiresInDays;
if(nExpireDays >= 0)
{
pwe.Expires = true;
pwe.ExpiryTime = DateTime.Now.AddDays(nExpireDays);
}*/
if((parentGroup.IconId != PwIcon.Folder) && (parentGroup.IconId != PwIcon.FolderOpen) &&
(parentGroup.IconId != PwIcon.FolderPackage))
{
mEntryInDatabase.IconId = parentGroup.IconId; // Inherit icon from group
}
mEntryInDatabase.CustomIconUuid = parentGroup.CustomIconUuid;
/*
* KPDesktop
if(strDefaultSeq.Length == 0)
{
PwGroup pg = m_pwEntry.ParentGroup;
if(pg != null)
{
strDefaultSeq = pg.GetAutoTypeSequenceInherited();
if(strDefaultSeq.Length == 0)
{
if(PwDefs.IsTanEntry(m_pwEntry))
strDefaultSeq = PwDefs.DefaultAutoTypeSequenceTan;
else
strDefaultSeq = PwDefs.DefaultAutoTypeSequence;
}
}
}*/
mIsNew = true;
} else {
System.Diagnostics.Debug.Assert(entryId != null);
mEntryInDatabase = db.entries[entryId];
mIsNew = false;
}
mEntry = mEntryInDatabase.CloneDeep();
fillData();
View scrollView = FindViewById(Resource.Id.entry_scroll);
scrollView.ScrollBarStyle = ScrollbarStyles.InsideInset;
ImageButton iconButton = (ImageButton) FindViewById(Resource.Id.icon_button);
iconButton.Click += (sender, evt) => {
IconPickerActivity.Launch(this);
};
// Generate password button
Button generatePassword = (Button) FindViewById(Resource.Id.generate_button);
generatePassword.Click += (object sender, EventArgs e) => {
GeneratePasswordActivity.Launch(this);
};
// Save button
Button save = (Button) FindViewById(Resource.Id.entry_save);
save.Click += (object sender, EventArgs e) =>
{
EntryEditActivity act = this;
if (!validateBeforeSaving())
return;
PwEntry initialEntry = mEntryInDatabase.CloneDeep();
PwEntry newEntry = mEntryInDatabase;
//Clone history and re-assign:
newEntry.History = newEntry.History.CloneDeep();
//Based on KeePass Desktop
bool bCreateBackup = (!mIsNew);
if(bCreateBackup) newEntry.CreateBackup(null);
if (mSelectedIcon == false) {
if (mIsNew) {
newEntry.IconId = PwIcon.Key;
} else {
// Keep previous icon, if no new one was selected
}
}
else {
newEntry.IconId = mSelectedIconID;
newEntry.CustomIconUuid = mSelectedCustomIconID;
}
/* KPDesktop
if(m_cbCustomForegroundColor.Checked)
newEntry.ForegroundColor = m_clrForeground;
else newEntry.ForegroundColor = Color.Empty;
if(m_cbCustomBackgroundColor.Checked)
newEntry.BackgroundColor = m_clrBackground;
else newEntry.BackgroundColor = Color.Empty;
*/
newEntry.Strings.Set(PwDefs.TitleField, new ProtectedString(db.pm.MemoryProtection.ProtectTitle,
Util.getEditText(act, Resource.Id.entry_title)));
newEntry.Strings.Set(PwDefs.UserNameField, new ProtectedString(db.pm.MemoryProtection.ProtectUserName,
Util.getEditText(act, Resource.Id.entry_user_name)));
String pass = Util.getEditText(act, Resource.Id.entry_password);
byte[] password = StrUtil.Utf8.GetBytes(pass);
newEntry.Strings.Set(PwDefs.PasswordField, new ProtectedString(db.pm.MemoryProtection.ProtectPassword,
password));
MemUtil.ZeroByteArray(password);
newEntry.Strings.Set(PwDefs.UrlField, new ProtectedString(db.pm.MemoryProtection.ProtectUrl,
Util.getEditText(act, Resource.Id.entry_url)));
newEntry.Strings.Set(PwDefs.NotesField, new ProtectedString(db.pm.MemoryProtection.ProtectNotes,
Util.getEditText(act, Resource.Id.entry_comment)));
// Delete all non standard strings
var keys = newEntry.Strings.GetKeys();
foreach (String key in keys)
if (PwDefs.IsStandardField(key) == false)
newEntry.Strings.Remove(key);
LinearLayout container = (LinearLayout) FindViewById(Resource.Id.advanced_container);
for (int index = 0; index < container.ChildCount; index++) {
View view = container.GetChildAt(index);
TextView keyView = (TextView)view.FindViewById(Resource.Id.title);
String key = keyView.Text;
TextView valueView = (TextView)view.FindViewById(Resource.Id.value);
String value = valueView.Text;
CheckBox cb = (CheckBox)view.FindViewById(Resource.Id.protection);
bool protect = cb.Checked;
newEntry.Strings.Set(key, new ProtectedString(protect, value));
}
newEntry.Binaries = mEntry.Binaries;
newEntry.Expires = mEntry.Expires;
if (newEntry.Expires)
{
newEntry.ExpiryTime = mEntry.ExpiryTime;
}
newEntry.OverrideUrl = Util.getEditText(this,Resource.Id.entry_override_url);
List<string> vNewTags = StrUtil.StringToTags(Util.getEditText(this,Resource.Id.entry_tags));
newEntry.Tags.Clear();
foreach(string strTag in vNewTags) newEntry.AddTag(strTag);
/*KPDesktop
m_atConfig.Enabled = m_cbAutoTypeEnabled.Checked;
m_atConfig.ObfuscationOptions = (m_cbAutoTypeObfuscation.Checked ?
AutoTypeObfuscationOptions.UseClipboard :
AutoTypeObfuscationOptions.None);
SaveDefaultSeq();
newEntry.AutoType = m_atConfig;
*/
newEntry.Touch(true, false); // Touch *after* backup
StrUtil.NormalizeNewLines(newEntry.Strings, true);
bool bUndoBackup = false;
PwCompareOptions cmpOpt = (PwCompareOptions.NullEmptyEquivStd |
PwCompareOptions.IgnoreTimes);
if(bCreateBackup) cmpOpt |= PwCompareOptions.IgnoreLastBackup;
if(newEntry.EqualsEntry(initialEntry, cmpOpt, MemProtCmpMode.CustomOnly))
{
// No modifications at all => restore last mod time and undo backup
newEntry.LastModificationTime = initialEntry.LastModificationTime;
bUndoBackup = bCreateBackup;
}
else if(bCreateBackup)
{
// If only history items have been modified (deleted) => undo
// backup, but without restoring the last mod time
PwCompareOptions cmpOptNH = (cmpOpt | PwCompareOptions.IgnoreHistory);
if(newEntry.EqualsEntry(initialEntry, cmpOptNH, MemProtCmpMode.CustomOnly))
bUndoBackup = true;
}
if(bUndoBackup) newEntry.History.RemoveAt(newEntry.History.UCount - 1);
newEntry.MaintainBackups(db.pm);
//if ( newEntry.Strings.ReadSafe (PwDefs.TitleField).Equals(mEntry.Strings.ReadSafe (PwDefs.TitleField)) ) {
// SetResult(KeePass.EXIT_REFRESH);
//} else {
//it's safer to always update the title as we might add further information in the title like expiry etc.
SetResult(KeePass.EXIT_REFRESH_TITLE);
//}
RunnableOnFinish task;
OnFinish onFinish = new AfterSave(new Handler(), act);
if ( mIsNew ) {
task = AddEntry.getInstance(this, App.getDB(), newEntry, parentGroup, onFinish);
} else {
task = new UpdateEntry(this, App.getDB(), initialEntry, newEntry, onFinish);
}
ProgressTask pt = new ProgressTask(act, task, Resource.String.saving_database);
pt.run();
};
// Respect mask password setting
if (mShowPassword) {
EditText pass = (EditText) FindViewById(Resource.Id.entry_password);
EditText conf = (EditText) FindViewById(Resource.Id.entry_confpassword);
pass.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
conf.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
}
scroll = (ScrollView) FindViewById(Resource.Id.entry_scroll);
Button addButton = (Button) FindViewById(Resource.Id.add_advanced);
addButton.Visibility = ViewStates.Visible;
addButton.Click += (object sender, EventArgs e) =>
{
LinearLayout container = (LinearLayout) FindViewById(Resource.Id.advanced_container);
EntryEditSection ees = (EntryEditSection) LayoutInflater.Inflate(Resource.Layout.entry_edit_section, null);
ees.setData("", new ProtectedString(false, ""));
ees.getDeleteButton().Click += (senderEes, eEes) => deleteAdvancedString((View)senderEes);
container.AddView(ees);
// Scroll bottom
scroll.Post(() => {
scroll.FullScroll(FocusSearchDirection.Down);
});
};
((CheckBox)FindViewById(Resource.Id.entry_expires_checkbox)).CheckedChange += (object sender, CompoundButton.CheckedChangeEventArgs e) =>
{
mEntry.Expires = e.IsChecked;
if (e.IsChecked)
{
if (mEntry.ExpiryTime < DateTime.Now)
mEntry.ExpiryTime = DateTime.Now;
}
updateExpires();
};
}
void addBinaryOrAsk(string filename)
{
string strItem = UrlUtil.GetFileName(filename);
if(mEntry.Binaries.Get(strItem) != null)
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.SetTitle(GetString(Resource.String.AskOverwriteBinary_title));
builder.SetMessage(GetString(Resource.String.AskOverwriteBinary));
builder.SetPositiveButton(GetString(Resource.String.AskOverwriteBinary_yes), new EventHandler<DialogClickEventArgs>((dlgSender, dlgEvt) =>
{
addBinary(filename, true);
}));
builder.SetNegativeButton(GetString(Resource.String.AskOverwriteBinary_no), new EventHandler<DialogClickEventArgs>((dlgSender, dlgEvt) =>
{
addBinary(filename, false);
}));
builder.SetNeutralButton(GetString(Android.Resource.String.Cancel),
new EventHandler<DialogClickEventArgs>((dlgSender, dlgEvt) => {}));
Dialog dialog = builder.Create();
dialog.Show();
} else
addBinary(filename, true);
}
void addBinary(string filename, bool overwrite)
{
string strItem = UrlUtil.GetFileName(filename);
if (!overwrite)
{
string strFileName = UrlUtil.StripExtension(strItem);
string strExtension = "." + UrlUtil.GetExtension(strItem);
int nTry = 0;
while(true)
{
string strNewName = strFileName + nTry.ToString() + strExtension;
if(mEntry.Binaries.Get(strNewName) == null)
{
strItem = strNewName;
break;
}
++nTry;
}
}
try
{
byte[] vBytes = File.ReadAllBytes(filename);
if(vBytes != null)
{
ProtectedBinary pb = new ProtectedBinary(false, vBytes);
mEntry.Binaries.Set(strItem, pb);
}
}
catch(Exception exAttach)
{
Toast.MakeText(this, GetString(Resource.String.AttachFailed)+" "+exAttach.Message, ToastLength.Long).Show();
}
populateBinaries();
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
switch ((int)resultCode)
{
case RESULT_OK_ICON_PICKER:
mSelectedIconID = (PwIcon) data.Extras.GetInt(IconPickerActivity.KEY_ICON_ID);
mSelectedCustomIconID = PwUuid.Zero;
String customIconIdString = data.Extras.GetString(IconPickerActivity.KEY_CUSTOM_ICON_ID);
if (!String.IsNullOrEmpty(customIconIdString))
mSelectedCustomIconID = new PwUuid(MemUtil.HexStringToByteArray(customIconIdString));
mSelectedIcon = true;
ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button);
//TODO: custom image
currIconButton.SetImageResource(Icons.iconToResId(mSelectedIconID));
break;
case RESULT_OK_PASSWORD_GENERATOR:
String generatedPassword = data.GetStringExtra("keepass2android.password.generated_password");
EditText password = (EditText) FindViewById(Resource.Id.entry_password);
EditText confPassword = (EditText) FindViewById(Resource.Id.entry_confpassword);
password.Text = generatedPassword;
confPassword.Text = generatedPassword;
break;
case (int)Result.Ok:
if (requestCode == Intents.REQUEST_CODE_FILE_BROWSE)
{
String filename = data.DataString;
if (filename != null) {
if (filename.StartsWith("file://")) {
filename = filename.Substring(7);
}
filename = Java.Net.URLDecoder.Decode(filename);
addBinaryOrAsk(filename);
}
}
break;
case (int)Result.Canceled:
break;
default:
break;
}
}
void populateBinaries()
{
ViewGroup binariesGroup = (ViewGroup)FindViewById(Resource.Id.binaries);
binariesGroup.RemoveAllViews();
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FillParent, RelativeLayout.LayoutParams.WrapContent);
foreach (KeyValuePair<string, ProtectedBinary> pair in mEntry.Binaries)
{
String key = pair.Key;
Button binaryButton = new Button(this);
binaryButton.Text = key;
binaryButton.SetCompoundDrawablesWithIntrinsicBounds( Resources.GetDrawable(Android.Resource.Drawable.IcMenuDelete),null, null, null);
binaryButton.Click += (object sender, EventArgs e) =>
{
Button btnSender = (Button)(sender);
mEntry.Binaries.Remove(key);
populateBinaries();
};
binariesGroup.AddView(binaryButton,layoutParams);
}
Button addBinaryButton = new Button(this);
addBinaryButton.Text = GetString(Resource.String.add_binary);
addBinaryButton.SetCompoundDrawablesWithIntrinsicBounds( Resources.GetDrawable(Android.Resource.Drawable.IcMenuAdd) , null, null, null);
addBinaryButton.Click += (object sender, EventArgs e) =>
{
Util.showBrowseDialog("/mnt/sdcard", this);
};
binariesGroup.AddView(addBinaryButton,layoutParams);
FindViewById(Resource.Id.entry_binaries_label).Visibility = mEntry.Binaries.UCount > 0 ? ViewStates.Visible : ViewStates.Gone;
}
public override bool OnCreateOptionsMenu(IMenu menu) {
base.OnCreateOptionsMenu(menu);
MenuInflater inflater = MenuInflater;
inflater.Inflate(Resource.Menu.entry_edit, menu);
IMenuItem togglePassword = menu.FindItem(Resource.Id.menu_toggle_pass);
if ( mShowPassword ) {
togglePassword.SetTitle(Resource.String.menu_hide_password);
} else {
togglePassword.SetTitle(Resource.String.show_password);
}
return true;
}
public override bool OnOptionsItemSelected(IMenuItem item) {
switch ( item.ItemId ) {
/*case Resource.Id.menu_donate:
try {
Util.gotoUrl(this, Resource.String.donate_url);
} catch (ActivityNotFoundException) {
Toast.MakeText(this, Resource.String.error_failed_to_launch_link, ToastLength.Long).Show();
return false;
}
return true;*/
case Resource.Id.menu_toggle_pass:
if ( mShowPassword ) {
item.SetTitle(Resource.String.show_password);
mShowPassword = false;
} else {
item.SetTitle(Resource.String.menu_hide_password);
mShowPassword = true;
}
setPasswordStyle();
return true;
case Resource.Id.menu_cancel_edit:
Finish();
break;
}
return base.OnOptionsItemSelected(item);
}
private void setPasswordStyle() {
TextView password = (TextView) FindViewById(Resource.Id.entry_password);
TextView confpassword = (TextView) FindViewById(Resource.Id.entry_confpassword);
if ( mShowPassword ) {
password.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
confpassword.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
} else {
password.InputType = InputTypes.ClassText | InputTypes.TextVariationPassword;
confpassword.InputType = InputTypes.ClassText | InputTypes.TextVariationPassword;
}
}
void updateExpires()
{
if (mEntry.Expires)
{
populateText(Resource.Id.entry_expires, getDateTime(mEntry.ExpiryTime));
}
else
{
populateText(Resource.Id.entry_expires, GetString(Resource.String.never));
}
((CheckBox)FindViewById(Resource.Id.entry_expires_checkbox)).Checked = mEntry.Expires;
((EditText)FindViewById(Resource.Id.entry_expires)).Enabled = mEntry.Expires;
}
private void fillData() {
ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button);
App.getDB().drawFactory.assignDrawableTo(currIconButton, Resources, App.getDB().pm, mEntry.IconId, mEntry.CustomIconUuid);
populateText(Resource.Id.entry_title, mEntry.Strings.ReadSafe (PwDefs.TitleField));
populateText(Resource.Id.entry_user_name, mEntry.Strings.ReadSafe (PwDefs.UserNameField));
populateText(Resource.Id.entry_url, mEntry.Strings.ReadSafe (PwDefs.UrlField));
String password = mEntry.Strings.ReadSafe(PwDefs.PasswordField);
populateText(Resource.Id.entry_password, password);
populateText(Resource.Id.entry_confpassword, password);
setPasswordStyle();
populateText(Resource.Id.entry_comment, mEntry.Strings.ReadSafe (PwDefs.NotesField));
LinearLayout container = (LinearLayout) FindViewById(Resource.Id.advanced_container);
foreach (var pair in mEntry.Strings)
{
String key = pair.Key;
if (!PwDefs.IsStandardField(key)) {
EntryEditSection ees = (EntryEditSection) LayoutInflater.Inflate(Resource.Layout.entry_edit_section, null);
ees.setData(key, pair.Value);
ees.getDeleteButton().Click += (sender, e) => deleteAdvancedString((View)sender);
container.AddView(ees);
}
}
populateBinaries();
populateText(Resource.Id.entry_override_url, mEntry.OverrideUrl);
populateText(Resource.Id.entry_tags, StrUtil.TagsToString(mEntry.Tags, true));
updateExpires();
}
private String getDateTime(System.DateTime dt) {
return dt.ToString ("g", CultureInfo.CurrentUICulture);
}
public void deleteAdvancedString(View view) {
EntryEditSection section = (EntryEditSection) view.Parent;
LinearLayout container = (LinearLayout) FindViewById(Resource.Id.advanced_container);
for (int i = 0; i < container.ChildCount; i++) {
EntryEditSection ees = (EntryEditSection) container.GetChildAt(i);
if (ees == section) {
container.RemoveViewAt(i);
container.Invalidate();
break;
}
}
}
protected bool validateBeforeSaving() {
// Require title
String title = Util.getEditText(this, Resource.Id.entry_title);
if ( title.Length == 0 ) {
Toast.MakeText(this, Resource.String.error_title_required, ToastLength.Long).Show();
return false;
}
// Validate password
String pass = Util.getEditText(this, Resource.Id.entry_password);
String conf = Util.getEditText(this, Resource.Id.entry_confpassword);
if ( ! pass.Equals(conf) ) {
Toast.MakeText(this, Resource.String.error_pass_match, ToastLength.Long).Show();
return false;
}
// Validate expiry date
DateTime newExpiry = new DateTime();
if ((mEntry.Expires) && (!DateTime.TryParse( Util.getEditText(this,Resource.Id.entry_expires), out newExpiry)))
{
Toast.MakeText(this, Resource.String.error_invalid_expiry_date, ToastLength.Long).Show();
return false;
}
else
{
mEntry.ExpiryTime = newExpiry;
}
LinearLayout container = (LinearLayout) FindViewById(Resource.Id.advanced_container);
for (int i = 0; i < container.ChildCount; i++) {
EntryEditSection ees = (EntryEditSection) container.GetChildAt(i);
TextView keyView = (TextView) ees.FindViewById(Resource.Id.title);
string key = keyView.Text;
if (String.IsNullOrEmpty(key)) {
Toast.MakeText(this, Resource.String.error_string_key, ToastLength.Long).Show();
return false;
}
}
return true;
}
private void populateText(int viewId, String text) {
TextView tv = (TextView) FindViewById(viewId);
tv.Text = text;
}
private class AfterSave : OnFinish {
Activity act;
public AfterSave(Handler handler, Activity act): base(handler) {
this.act = act;
}
public override void run() {
if ( mSuccess ) {
act.Finish();
} else {
displayMessage(act);
}
}
}
}
}

View File

@@ -0,0 +1,130 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace keepass2android
{
[Activity (Label = "@string/app_name", Theme="@style/NoTitleBar")]
public class GeneratePasswordActivity : LockCloseActivity {
private int[] BUTTON_IDS = new int[] {Resource.Id.btn_length6, Resource.Id.btn_length8, Resource.Id.btn_length12, Resource.Id.btn_length16};
public static void Launch(Activity act) {
Intent i = new Intent(act, typeof(GeneratePasswordActivity));
act.StartActivityForResult(i, 0);
}
protected override void OnCreate(Bundle savedInstanceState) {
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.generate_password);
SetResult(KeePass.EXIT_NORMAL);
foreach (int id in BUTTON_IDS) {
Button button = (Button) FindViewById(id);
button.Click += (object sender, EventArgs e) =>
{
Button b = (Button) sender;
EditText editText = (EditText) FindViewById(Resource.Id.length);
editText.Text = b.Text;
};
}
Button genPassButton = (Button) FindViewById(Resource.Id.generate_password_button);
genPassButton.Click += (object sender, EventArgs e) => {
String password = generatePassword();
EditText txtPassword = (EditText) FindViewById(Resource.Id.password);
txtPassword.Text = password;
};
Button acceptButton = (Button) FindViewById(Resource.Id.accept_button);
acceptButton.Click += (object sender, EventArgs e) => {
EditText password = (EditText) FindViewById(Resource.Id.password);
Intent intent = new Intent();
intent.PutExtra("keepass2android.password.generated_password", password.Text);
SetResult((Result)EntryEditActivity.RESULT_OK_PASSWORD_GENERATOR, intent);
Finish();
};
Button cancelButton = (Button) FindViewById(Resource.Id.cancel_button);
cancelButton.Click += (object sender, EventArgs e) =>
{
SetResult(Result.Canceled);
Finish();
};
EditText txtPasswordToSet = (EditText) FindViewById(Resource.Id.password);
txtPasswordToSet.Text = generatePassword();
}
public String generatePassword() {
String password = "";
try {
int length;
if (!int.TryParse(((EditText) FindViewById(Resource.Id.length)).Text, out length))
{
Toast.MakeText(this, Resource.String.error_wrong_length, ToastLength.Long).Show();
return password;
}
PasswordGenerator generator = new PasswordGenerator(this);
password = generator.generatePassword(length,
((CheckBox) FindViewById(Resource.Id.cb_uppercase)).Checked,
((CheckBox) FindViewById(Resource.Id.cb_lowercase)).Checked,
((CheckBox) FindViewById(Resource.Id.cb_digits)).Checked,
((CheckBox) FindViewById(Resource.Id.cb_minus)).Checked,
((CheckBox) FindViewById(Resource.Id.cb_underline)).Checked,
((CheckBox) FindViewById(Resource.Id.cb_space)).Checked,
((CheckBox) FindViewById(Resource.Id.cb_specials)).Checked,
((CheckBox) FindViewById(Resource.Id.cb_brackets)).Checked);
} catch (ArgumentException e) {
Toast.MakeText(this, e.Message, ToastLength.Long).Show();
}
return password;
}
}
}

View File

@@ -0,0 +1,195 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using KeePassLib;
using Android.Util;
using KeePassLib.Utility;
using keepass2android.view;
using Android.Content.PM;
namespace keepass2android
{
[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden , Theme="@style/NoTitleBar")]
[MetaData("android.app.default_searchable",Value="keepass2android.search.SearchResults")]
public class GroupActivity : GroupBaseActivity {
public const int UNINIT = -1;
protected bool addGroupEnabled = false;
protected bool addEntryEnabled = false;
private const String TAG = "Group Activity:";
public static void Launch(Activity act) {
Launch(act, null);
}
public static void Launch (Activity act, PwGroup g)
{
Intent i;
// Need to use PwDatabase since group may be null
PwDatabase db = App.getDB ().pm;
if (db == null) {
// Reached if db is null
Log.Debug (TAG, "Tried to launch with null db");
return;
}
i = new Intent(act, typeof(GroupActivity));
if ( g != null ) {
i.PutExtra(KEY_ENTRY, g.Uuid.ToHexString());
}
act.StartActivityForResult(i,0);
}
protected PwUuid retrieveGroupId(Intent i)
{
String uuid = i.GetStringExtra(KEY_ENTRY);
if ( String.IsNullOrEmpty(uuid) ) {
return null;
}
return new PwUuid(MemUtil.HexStringToByteArray(uuid));
}
protected void setupButtons()
{
addGroupEnabled = true;
addEntryEnabled = !mGroup.Uuid.EqualsValue(App.getDB().root.Uuid);
}
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
if (IsFinishing) {
return;
}
SetResult (KeePass.EXIT_NORMAL);
Log.Warn (TAG, "Creating group view");
Intent intent = Intent;
PwUuid id = retrieveGroupId (intent);
Database db = App.getDB ();
if (id == null) {
mGroup = db.root;
} else {
mGroup = db.groups[id];
}
Log.Warn (TAG, "Retrieved group");
if (mGroup == null) {
Log.Warn (TAG, "Group was null");
return;
}
setupButtons ();
if (addGroupEnabled && addEntryEnabled) {
SetContentView (new GroupAddEntryView (this));
} else if (addGroupEnabled) {
SetContentView (new GroupRootView (this));
} else if (addEntryEnabled) {
throw new Exception ("This mode is not supported.");
} else {
SetContentView (new GroupViewOnlyView (this));
}
Log.Warn (TAG, "Set view");
if (addGroupEnabled) {
// Add Group button
Button addGroup = (Button)FindViewById (Resource.Id.add_group);
addGroup.Click += (object sender, EventArgs e) => {
GroupEditActivity.Launch (this, mGroup);
};
}
if (addEntryEnabled) {
// Add Entry button
Button addEntry = (Button)FindViewById (Resource.Id.add_entry);
addEntry.Click += (object sender, EventArgs e) => {
EntryEditActivity.Launch (this, mGroup);
};
}
setGroupTitle();
setGroupIcon();
ListAdapter = new PwGroupListAdapter(this, mGroup);
RegisterForContextMenu(ListView);
Log.Warn(TAG, "Finished creating group");
}
public override void OnCreateContextMenu(IContextMenu menu, View v,
IContextMenuContextMenuInfo menuInfo) {
AdapterView.AdapterContextMenuInfo acmi = (AdapterView.AdapterContextMenuInfo) menuInfo;
ClickView cv = (ClickView) acmi.TargetView;
cv.OnCreateMenu(menu, menuInfo);
}
public override bool OnContextItemSelected(IMenuItem item) {
Android.Widget.AdapterView.AdapterContextMenuInfo acmi = (Android.Widget.AdapterView.AdapterContextMenuInfo)item.MenuInfo;
ClickView cv = (ClickView) acmi.TargetView;
return cv.OnContextItemSelected(item);
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
switch (resultCode)
{
case Result.Ok:
String GroupName = data.Extras.GetString(GroupEditActivity.KEY_NAME);
int GroupIconID = data.Extras.GetInt(GroupEditActivity.KEY_ICON_ID);
GroupBaseActivity act = this;
Handler handler = new Handler();
AddGroup task = AddGroup.getInstance(this, App.getDB(), GroupName, GroupIconID, mGroup, new RefreshTask(handler, this), false);
ProgressTask pt = new ProgressTask(act, task, Resource.String.saving_database);
pt.run();
break;
case Result.Canceled:
default:
break;
}
}
}
}

View File

@@ -0,0 +1,295 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using KeePassLib;
using Android.Preferences;
using keepass2android.view;
namespace keepass2android
{
public abstract class GroupBaseActivity : LockCloseListActivity {
public const String KEY_ENTRY = "entry";
public const String KEY_MODE = "mode";
public virtual void LaunchActivityForEntry(KeePassLib.PwEntry pwEntry, int pos)
{
EntryActivity.Launch(this, pwEntry, pos, false);
}
public GroupBaseActivity ()
{
}
public GroupBaseActivity (IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
private ISharedPreferences prefs;
protected PwGroup mGroup;
protected override void OnResume() {
base.OnResume();
refreshIfDirty();
}
public override bool OnSearchRequested()
{
StartActivityForResult(typeof(SearchActivity), 0);
return true;
}
public void refreshIfDirty() {
Database db = App.getDB();
if ( db.dirty.Contains(mGroup) ) {
db.dirty.Remove(mGroup);
BaseAdapter adapter = (BaseAdapter) ListAdapter;
adapter.NotifyDataSetChanged();
}
}
protected override void OnListItemClick(ListView l, View v, int position, long id) {
base.OnListItemClick(l, v, position, id);
Android.Widget.IListAdapter adapt = ListAdapter;
ClickView cv = (ClickView) adapt.GetView(position, null, null);
cv.OnClick();
}
protected override void OnCreate(Bundle savedInstanceState) {
base.OnCreate(savedInstanceState);
// Likely the app has been killed exit the activity
if ( ! App.getDB().Loaded ) {
Finish();
return;
}
prefs = PreferenceManager.GetDefaultSharedPreferences(this);
SetContentView(new GroupViewOnlyView(this));
SetResult(KeePass.EXIT_NORMAL);
styleScrollBars();
}
protected void styleScrollBars() {
ListView lv = ListView;
lv.ScrollBarStyle =ScrollbarStyles.InsideInset;
lv.TextFilterEnabled = true;
}
protected void setGroupTitle()
{
Button tv = (Button)FindViewById(Resource.Id.group_name);
if (tv == null)
return;
if (mGroup != null)
{
String name = mGroup.Name;
if (!String.IsNullOrEmpty(name))
{
tv.Text = name;
} else
{
tv.Text = GetText(Resource.String.root);
}
}
if ((mGroup != null) && (mGroup.IsVirtual == false) && (mGroup.ParentGroup != null))
{
tv.Click += (object sender, EventArgs e) =>
{
Finish();
};
} else
{
tv.SetCompoundDrawables(null, null, null, null);
tv.Clickable = false;
}
}
protected void setGroupIcon() {
if (mGroup != null) {
ImageView iv = (ImageView) FindViewById(Resource.Id.icon);
App.getDB().drawFactory.assignDrawableTo(iv, Resources, App.getDB().pm, mGroup.IconId, mGroup.CustomIconUuid);
}
}
public override bool OnCreateOptionsMenu(IMenu menu) {
base.OnCreateOptionsMenu(menu);
MenuInflater inflater = MenuInflater;
inflater.Inflate(Resource.Menu.group, menu);
return true;
}
private void setSortMenuText(IMenu menu) {
bool sortByName = prefs.GetBoolean(GetString(Resource.String.sort_key), Resources.GetBoolean(Resource.Boolean.sort_default));
int resId;
if ( sortByName ) {
resId = Resource.String.sort_db;
} else {
resId = Resource.String.sort_name;
}
menu.FindItem(Resource.Id.menu_sort).SetTitle(resId);
}
public override bool OnPrepareOptionsMenu(IMenu menu) {
if ( ! base.OnPrepareOptionsMenu(menu) ) {
return false;
}
setSortMenuText(menu);
return true;
}
public override bool OnOptionsItemSelected(IMenuItem item) {
switch ( item.ItemId ) {
/*case Resource.Id.menu_donate:
try {
Util.gotoUrl(this, Resource.String.donate_url);
} catch (ActivityNotFoundException) {
Toast.MakeText(this, Resource.String.error_failed_to_launch_link, ToastLength.Long).Show();
return false;
}
return true;*/
case Resource.Id.menu_lock:
App.setShutdown();
SetResult(KeePass.EXIT_LOCK);
Finish();
return true;
case Resource.Id.menu_search:
OnSearchRequested();
return true;
case Resource.Id.menu_app_settings:
AppSettingsActivity.Launch(this);
return true;
case Resource.Id.menu_change_master_key:
setPassword();
return true;
case Resource.Id.menu_sort:
toggleSort();
return true;
}
return base.OnOptionsItemSelected(item);
}
private void toggleSort() {
// Toggle setting
String sortKey = GetString(Resource.String.sort_key);
bool sortByName = prefs.GetBoolean(sortKey, Resources.GetBoolean(Resource.Boolean.sort_default));
ISharedPreferencesEditor editor = prefs.Edit();
editor.PutBoolean(sortKey, ! sortByName);
EditorCompat.apply(editor);
// Refresh menu titles
ActivityCompat.invalidateOptionsMenu(this);
// Mark all groups as dirty now to refresh them on load
Database db = App.getDB();
db.markAllGroupsAsDirty();
// We'll manually refresh this group so we can remove it
db.dirty.Remove(mGroup);
// Tell the adapter to refresh it's list
BaseAdapter adapter = (BaseAdapter) ListAdapter;
adapter.NotifyDataSetChanged();
}
private void setPassword() {
SetPasswordDialog dialog = new SetPasswordDialog(this);
dialog.Show();
}
public class RefreshTask : OnFinish {
GroupBaseActivity act;
public RefreshTask(Handler handler, GroupBaseActivity act):base(handler) {
this.act = act;
}
public override void run() {
if ( mSuccess) {
act.refreshIfDirty();
} else {
displayMessage(act);
}
}
}
public class AfterDeleteGroup : OnFinish {
GroupBaseActivity act;
public AfterDeleteGroup(Handler handler, GroupBaseActivity act):base(handler) {
this.act = act;
}
public override void run() {
if ( mSuccess) {
act.refreshIfDirty();
} else {
mHandler.Post( () => {
Toast.MakeText(act, "Unrecoverable error: " + mMessage, ToastLength.Long).Show();
});
App.setShutdown();
act.Finish();
}
}
}
}
}

View File

@@ -0,0 +1,109 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using KeePassLib;
namespace keepass2android
{
[Activity (Label = "@string/app_name", Theme="@style/Dialog")]
public class GroupEditActivity : LifecycleDebugActivity
{
public const String KEY_PARENT = "parent";
public const String KEY_NAME = "name";
public const String KEY_ICON_ID = "icon_id";
private int mSelectedIconID;
public static void Launch(Activity act, PwGroup pw)
{
Intent i = new Intent(act, typeof(GroupEditActivity));
PwGroup parent = pw;
i.PutExtra(KEY_PARENT, parent.Uuid.ToHexString());
act.StartActivityForResult(i, 0);
}
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
SetContentView (Resource.Layout.group_edit);
SetTitle (Resource.String.add_group_title);
ImageButton iconButton = (ImageButton)FindViewById (Resource.Id.icon_button);
iconButton.Click += (object sender, EventArgs e) =>
{
IconPickerActivity.Launch (this);
};
mSelectedIconID = (int) PwIcon.FolderOpen;
iconButton.SetImageResource(Icons.iconToResId((PwIcon)mSelectedIconID));
Button okButton = (Button)FindViewById (Resource.Id.ok);
okButton.Click += (object sender, EventArgs e) => {
TextView nameField = (TextView)FindViewById (Resource.Id.group_name);
String name = nameField.Text;
if (name.Length > 0) {
Intent intent = new Intent ();
intent.PutExtra (KEY_NAME, name);
intent.PutExtra (KEY_ICON_ID, mSelectedIconID);
SetResult (Result.Ok, intent);
Finish ();
} else {
Toast.MakeText (this, Resource.String.error_no_name, ToastLength.Long).Show ();
}
};
Button cancel = (Button)FindViewById (Resource.Id.cancel);
cancel.Click += (object sender, EventArgs e) => {
Intent intent = new Intent ();
SetResult (Result.Canceled, intent);
Finish ();
};
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
switch ((int)resultCode)
{
case EntryEditActivity.RESULT_OK_ICON_PICKER:
mSelectedIconID = data.Extras.GetInt(IconPickerActivity.KEY_ICON_ID);
ImageButton currIconButton = (ImageButton) FindViewById(Resource.Id.icon_button);
currIconButton.SetImageResource(Icons.iconToResId((PwIcon)mSelectedIconID));
break;
default:
break;
}
}
}
}

View File

@@ -0,0 +1,118 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace keepass2android
{
[Activity (Label = "@string/app_name", Theme="@style/NoTitleBar")]
public class IconPickerActivity : LockCloseActivity
{
public const String KEY_ICON_ID = "icon_id";
public const String KEY_CUSTOM_ICON_ID = "custom_icon_id";
public static void Launch(Activity act)
{
Intent i = new Intent(act, typeof(IconPickerActivity));
act.StartActivityForResult(i, 0);
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.icon_picker);
GridView currIconGridView = (GridView)FindViewById(Resource.Id.IconGridView);
currIconGridView.Adapter = new ImageAdapter(this, this);
currIconGridView.ItemClick += (sender, e) => {
Intent intent = new Intent();
intent.PutExtra(KEY_ICON_ID, e.Position);
SetResult((Result)EntryEditActivity.RESULT_OK_ICON_PICKER, intent);
Finish();
};
}
public class ImageAdapter : BaseAdapter
{
Context mContext;
IconPickerActivity act;
public ImageAdapter(Context c, IconPickerActivity act)
{
mContext = c;
this.act = act;
}
public override int Count
{
get
{
/* Return number of KeePass icons */
return Icons.count();
}
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return 0;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View currView;
if(convertView == null)
{
LayoutInflater li = (LayoutInflater) act.GetSystemService(Context.LayoutInflaterService);
currView = li.Inflate(Resource.Layout.icon, null);
}
else
{
currView = convertView;
}
TextView tv = (TextView) currView.FindViewById(Resource.Id.icon_text);
tv.Text = "" + position;
ImageView iv = (ImageView) currView.FindViewById(Resource.Id.icon_image);
iv.SetImageResource(Icons.iconToResId((KeePassLib.PwIcon)position));
return currView;
}
}
}
}

View File

@@ -0,0 +1,94 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using keepass2android.view;
namespace keepass2android
{
[Activity (Label = "@string/app_name", MainLauncher = true, Theme="@style/Base")]
[IntentFilter (new[]{Intent.ActionView},
DataScheme="file",
DataMimeType="*/*",
DataHost="*",
DataPathPattern=".*\\.kdbx", //TODO http://stackoverflow.com/questions/3400072/pathpattern-to-match-file-extension-does-not-work-if-a-period-exists-elsewhere-i
//http://stackoverflow.com/questions/1733195/android-intent-filter-for-a-particular-file-extension
Categories=new[]{Intent.CategoryDefault, Intent.CategoryBrowsable})]
public class KeePass : LifecycleDebugActivity
{
public const Android.App.Result EXIT_NORMAL = Android.App.Result.FirstUser;
public const Android.App.Result EXIT_LOCK = Android.App.Result.FirstUser+1;
public const Android.App.Result EXIT_REFRESH = Android.App.Result.FirstUser+2;
public const Android.App.Result EXIT_REFRESH_TITLE = Android.App.Result.FirstUser+3;
public const Android.App.Result EXIT_FORCE_LOCK = Android.App.Result.FirstUser+4;
public const Android.App.Result EXIT_QUICK_UNLOCK = Android.App.Result.FirstUser+5;
public const Android.App.Result EXIT_CLOSE_AFTER_SEARCH = Android.App.Result.FirstUser+6;
public const Android.App.Result EXIT_CHANGE_DB = Android.App.Result.FirstUser+7;
public const Android.App.Result EXIT_FORCE_LOCK_AND_CHANGE_DB = Android.App.Result.FirstUser+8;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
Android.Util.Log.Debug("DEBUG","KeePass.OnCreate");
}
protected override void OnResume()
{
base.OnResume();
Android.Util.Log.Debug("DEBUG","KeePass.OnResume");
}
protected override void OnStart() {
base.OnStart();
Android.Util.Log.Debug("DEBUG","KeePass.OnStart");
startFileSelect();
}
private void startFileSelect() {
Intent intent = new Intent(this, typeof(FileSelectActivity));
//TEST Intent intent = new Intent(this, typeof(EntryActivity));
//Intent intent = new Intent(this, typeof(SearchActivity));
//Intent intent = new Intent(this, typeof(QuickUnlock));
StartActivityForResult(intent, 0);
Finish();
}
protected override void OnDestroy() {
Android.Util.Log.Debug("DEBUG","KeePass.OnDestry"+IsFinishing.ToString());
base.OnDestroy();
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) {
base.OnActivityResult(requestCode, resultCode, data);
Finish();
}
}
}

View File

@@ -0,0 +1,71 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace keepass2android
{
[Serializable]
public class KeyFileException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="T:KeyFileException"/> class
/// </summary>
public KeyFileException ()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:KeyFileException"/> class
/// </summary>
/// <param name="message">A <see cref="T:System.String"/> that describes the exception. </param>
public KeyFileException (string message) : base (message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:KeyFileException"/> class
/// </summary>
/// <param name="message">A <see cref="T:System.String"/> that describes the exception. </param>
/// <param name="inner">The exception that is the cause of the current exception. </param>
public KeyFileException (string message, Exception inner) : base (message, inner)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:KeyFileException"/> class
/// </summary>
/// <param name="context">The contextual information about the source or destination.</param>
/// <param name="info">The object that holds the serialized object data.</param>
protected KeyFileException (System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base (info, context)
{
}
}
}

View File

@@ -0,0 +1,93 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace keepass2android
{
public abstract class LifecycleDebugActivity : Activity
{
public LifecycleDebugActivity (IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
public LifecycleDebugActivity()
{
}
string className = null;
string ClassName
{
get {
if (className == null)
className = this.GetType().Name;
return className;
}
}
protected override void OnResume()
{
base.OnResume();
Android.Util.Log.Debug("DEBUG",ClassName+".OnResume");
}
protected override void OnStart()
{
base.OnStart();
Android.Util.Log.Debug("DEBUG",ClassName+".OnStart");
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
Android.Util.Log.Debug("DEBUG",ClassName+".OnCreate");
}
protected override void OnDestroy()
{
base.OnDestroy();
Android.Util.Log.Debug("DEBUG",ClassName+".OnDestroy"+IsFinishing.ToString());
}
protected override void OnPause()
{
base.OnPause();
Android.Util.Log.Debug("DEBUG",ClassName+".OnPause");
}
protected override void OnStop()
{
base.OnStop();
Android.Util.Log.Debug("DEBUG",ClassName+".OnStop");
}
}
}

View File

@@ -0,0 +1,53 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using KeePassLib.Serialization;
namespace keepass2android
{
public class LockCloseActivity : LockingActivity {
IOConnectionInfo mIoc;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
mIoc = App.getDB().mIoc;
}
protected override void OnResume() {
base.OnResume();
TimeoutHelper.checkShutdown(this, mIoc);
}
}
}

View File

@@ -0,0 +1,61 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using KeePassLib.Serialization;
namespace keepass2android
{
public class LockCloseListActivity : LockingListActivity {
public LockCloseListActivity()
{
}
IOConnectionInfo mIoc;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
mIoc = App.getDB().mIoc;
}
public LockCloseListActivity (IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
protected override void OnResume() {
base.OnResume();
TimeoutHelper.checkShutdown(this, mIoc);
}
}
}

View File

@@ -0,0 +1,64 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace keepass2android
{
public class LockingActivity : LifecycleDebugActivity {
public LockingActivity (IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
public LockingActivity()
{
}
protected override void OnPause() {
base.OnPause();
TimeoutHelper.pause(this);
}
protected override void OnDestroy()
{
base.OnDestroy();
GC.Collect();
}
protected override void OnResume() {
base.OnResume();
TimeoutHelper.resume(this);
}
}
}

View File

@@ -0,0 +1,53 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using KeePassLib.Serialization;
namespace keepass2android
{
public class LockingClosePreferenceActivity : LockingPreferenceActivity {
IOConnectionInfo mIoc;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
mIoc = App.getDB().mIoc;
}
protected override void OnResume() {
base.OnResume();
TimeoutHelper.checkShutdown(this, mIoc);
}
}
}

View File

@@ -0,0 +1,96 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace keepass2android
{
public class LockingListActivity : ListActivity {
public LockingListActivity (IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
public LockingListActivity ()
{
}
string className = null;
string ClassName
{
get {
if (className == null)
className = this.GetType().Name;
return className;
}
}
protected override void OnResume()
{
base.OnResume();
TimeoutHelper.resume(this);
Android.Util.Log.Debug("DEBUG",ClassName+".OnResume");
}
protected override void OnStart()
{
base.OnStart();
Android.Util.Log.Debug("DEBUG",ClassName+".OnStart");
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
Android.Util.Log.Debug("DEBUG",ClassName+".OnCreate");
}
protected override void OnDestroy()
{
base.OnDestroy();
GC.Collect();
Android.Util.Log.Debug("DEBUG",ClassName+".OnDestroy"+IsFinishing.ToString());
}
protected override void OnPause()
{
base.OnPause();
TimeoutHelper.pause(this);
Android.Util.Log.Debug("DEBUG",ClassName+".OnPause");
}
protected override void OnStop()
{
base.OnStop();
Android.Util.Log.Debug("DEBUG",ClassName+".OnStop");
}
}
}

View File

@@ -0,0 +1,97 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Preferences;
namespace keepass2android
{
public class LockingPreferenceActivity : PreferenceActivity {
public LockingPreferenceActivity (IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
public LockingPreferenceActivity ()
{
}
string className = null;
string ClassName
{
get {
if (className == null)
className = this.GetType().Name;
return className;
}
}
protected override void OnResume()
{
base.OnResume();
TimeoutHelper.resume(this);
Android.Util.Log.Debug("DEBUG",ClassName+".OnResume");
}
protected override void OnStart()
{
base.OnStart();
Android.Util.Log.Debug("DEBUG",ClassName+".OnStart");
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
Android.Util.Log.Debug("DEBUG",ClassName+".OnCreate");
}
protected override void OnDestroy()
{
base.OnDestroy();
GC.Collect();
Android.Util.Log.Debug("DEBUG",ClassName+".OnDestroy"+IsFinishing.ToString());
}
protected override void OnPause()
{
base.OnPause();
TimeoutHelper.pause(this);
Android.Util.Log.Debug("DEBUG",ClassName+".OnPause");
}
protected override void OnStop()
{
base.OnStop();
Android.Util.Log.Debug("DEBUG",ClassName+".OnStop");
}
}
}

View File

@@ -0,0 +1,570 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Java.Net;
using Android.Preferences;
using Java.IO;
using Android.Text;
using Android.Content.PM;
using Android.Text.Method;
using KeePassLib.Keys;
using KeePassLib.Serialization;
namespace keepass2android
{
[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden, Theme="@style/Base")]
public class PasswordActivity : LockingActivity {
bool mShowPassword = false;
public const String KEY_DEFAULT_FILENAME = "defaultFileName";
public const String KEY_FILENAME = "fileName";
private const String KEY_KEYFILE = "keyFile";
private const String KEY_SERVERUSERNAME = "serverCredUser";
private const String KEY_SERVERPASSWORD = "serverCredPwd";
private const String KEY_SERVERCREDMODE = "serverCredRememberMode";
private const String VIEW_INTENT = "android.intent.action.VIEW";
private IOConnectionInfo mIoConnection;
private String mKeyFile;
private bool mRememberKeyfile;
ISharedPreferences prefs;
public PasswordActivity (IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
public PasswordActivity()
{
}
static void PutIoConnectionToIntent(IOConnectionInfo ioc, Android.Content.Intent i)
{
i.PutExtra(KEY_FILENAME, ioc.Path);
i.PutExtra(KEY_SERVERUSERNAME, ioc.UserName);
i.PutExtra(KEY_SERVERPASSWORD, ioc.Password);
i.PutExtra(KEY_SERVERCREDMODE, (int)ioc.CredSaveMode);
}
public static void SetIoConnectionFromIntent(IOConnectionInfo ioc, Intent i)
{
ioc.Path = i.GetStringExtra(KEY_FILENAME);
ioc.UserName = i.GetStringExtra(KEY_SERVERUSERNAME) ?? "";
ioc.Password = i.GetStringExtra(KEY_SERVERPASSWORD) ?? "";
ioc.CredSaveMode = (IOCredSaveMode)i.GetIntExtra(KEY_SERVERCREDMODE, (int) IOCredSaveMode.NoSave);
}
public static void Launch(Activity act, String fileName, String urlToSearchFor) {
Java.IO.File dbFile = new Java.IO.File(fileName);
if ( ! dbFile.Exists() ) {
throw new Java.IO.FileNotFoundException();
}
Intent i = new Intent(act, typeof(PasswordActivity));
i.PutExtra(KEY_FILENAME, fileName);
i.PutExtra(FileSelectActivity.UrlToSearch_key, urlToSearchFor);
act.StartActivityForResult(i, 0);
}
public static void Launch(Activity act, String fileName) {
Launch(act, IOConnectionInfo.FromPath(fileName), null);
}
public static void Launch(Activity act, IOConnectionInfo ioc, String urlToSearchFor)
{
if (ioc.IsLocalFile())
{
Launch(act, ioc.Path, urlToSearchFor);
return;
}
Intent i = new Intent(act, typeof(PasswordActivity));
PutIoConnectionToIntent(ioc, i);
i.PutExtra(FileSelectActivity.UrlToSearch_key, urlToSearchFor);
act.StartActivityForResult(i, 0);
}
public void LaunchNextActivity()
{
if (String.IsNullOrEmpty(mUrlToSearchFor))
GroupActivity.Launch(this);
else
{
ShareUrlResults.Launch(this, mUrlToSearchFor);
}
}
void unloadDatabase()
{
App.getDB().Clear();
StopService(new Intent(this, typeof(QuickUnlockForegroundService)));
}
void lockDatabase()
{
SetResult(KeePass.EXIT_LOCK);
setEditText(Resource.Id.password, "");
if (App.getDB().QuickUnlockEnabled)
App.getDB().Locked = true;
else
{
unloadDatabase();
}
}
void lockAndClose()
{
lockDatabase();
Finish();
}
bool tryStartQuickUnlock()
{
if (!App.getDB().QuickUnlockEnabled)
return false;
if (App.getDB().pm.MasterKey.ContainsType(typeof(KcpPassword)) == false)
return false;
KcpPassword kcpPassword = (KcpPassword)App.getDB().pm.MasterKey.GetUserKey(typeof(KcpPassword));
String password = kcpPassword.Password.ReadString();
if (password.Length == 0)
return false;
App.getDB().Locked = true;
Intent i = new Intent(this, typeof(QuickUnlock));
PutIoConnectionToIntent(mIoConnection, i);
Android.Util.Log.Debug("DEBUG","Starting QuickUnlock");
StartActivityForResult(i,0);
return true;
}
public void StartQuickUnlockForegroundService()
{
if (App.getDB().QuickUnlockEnabled)
{
StartService(new Intent(this, typeof(QuickUnlockForegroundService)));
}
}
bool startedWithActivityResult = false;
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
startedWithActivityResult = true;
Android.Util.Log.Debug("DEBUG","PasswordActivity.OnActivityResult "+resultCode+"/"+requestCode);
if (resultCode != KeePass.EXIT_CLOSE_AFTER_SEARCH)
{
//Stop service when app activity is left
StopService(new Intent(this, typeof(CopyToClipboardService)));
}
//NOTE: original code from k eepassdroid used switch ((Android.App.Result)requestCode) { (but doesn't work here, although k eepassdroid works)
switch(resultCode) {
case KeePass.EXIT_NORMAL:
if (!tryStartQuickUnlock())
{
setEditText(Resource.Id.password, "");
;
}
break;
case KeePass.EXIT_LOCK:
if (!tryStartQuickUnlock())
{
lockAndClose();
}
break;
case KeePass.EXIT_FORCE_LOCK:
setEditText(Resource.Id.password, "");
unloadDatabase();
break;
case KeePass.EXIT_FORCE_LOCK_AND_CHANGE_DB:
unloadDatabase();
Finish();
break;
case KeePass.EXIT_CHANGE_DB:
lockAndClose();
break;
case KeePass.EXIT_CLOSE_AFTER_SEARCH:
SetResult(KeePass.EXIT_CLOSE_AFTER_SEARCH);
Finish();
break;
case KeePass.EXIT_QUICK_UNLOCK:
App.getDB().Locked = false;
LaunchNextActivity();
break;
case Android.App.Result.Ok:
if (requestCode == Intents.REQUEST_CODE_FILE_BROWSE) {
String filename = data.DataString;
if (filename != null) {
if (filename.StartsWith("file://")) {
filename = filename.Substring(7);
}
filename = URLDecoder.Decode(filename);
EditText fn = (EditText) FindViewById(Resource.Id.pass_keyfile);
fn.Text = filename;
}
}
break;
}
}
internal string mUrlToSearchFor;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Intent i = Intent;
String action = i.Action;
prefs = PreferenceManager.GetDefaultSharedPreferences(this);
mRememberKeyfile = prefs.GetBoolean(GetString(Resource.String.keyfile_key), Resources.GetBoolean(Resource.Boolean.keyfile_default));
mIoConnection = new IOConnectionInfo();
if (action != null && action.Equals(VIEW_INTENT))
{
mIoConnection.Path = i.DataString;
if (! mIoConnection.Path.Substring(0, 7).Equals("file://"))
{
//TODO: this might no longer be required as we can handle http(s) and ftp as well (but we need server credentials therefore)
Toast.MakeText(this, Resource.String.error_can_not_handle_uri, ToastLength.Long).Show();
Finish();
return;
}
mIoConnection.Path = URLDecoder.Decode(mIoConnection.Path.Substring(7, mIoConnection.Path.Length));
if (mIoConnection.Path.Length == 0)
{
// No file name
Toast.MakeText(this, Resource.String.FileNotFound, ToastLength.Long).Show();
Finish();
return;
}
File dbFile = new File(mIoConnection.Path);
if (! dbFile.Exists())
{
// File does not exist
Toast.MakeText(this, Resource.String.FileNotFound, ToastLength.Long).Show();
Finish();
return;
}
mKeyFile = getKeyFile(mIoConnection.Path);
} else
{
SetIoConnectionFromIntent(mIoConnection, i);
mKeyFile = i.GetStringExtra(KEY_KEYFILE);
if (mKeyFile == null || mKeyFile.Length == 0)
{
mKeyFile = getKeyFile(mIoConnection.Path);
}
}
this.mUrlToSearchFor = i.GetStringExtra(FileSelectActivity.UrlToSearch_key);
SetContentView(Resource.Layout.password);
populateView();
Button confirmButton = (Button)FindViewById(Resource.Id.pass_ok);
confirmButton.Click += (object sender, EventArgs e) =>
{
String pass = GetEditText(Resource.Id.password);
String key = GetEditText(Resource.Id.pass_keyfile);
if (pass.Length == 0 && key.Length == 0)
{
errorMessage(Resource.String.error_nopass);
return;
}
String fileName = GetEditText(Resource.Id.filename);
// Clear before we load
unloadDatabase();
// Clear the shutdown flag
App.clearShutdown();
CheckBox cbQuickUnlock = (CheckBox)FindViewById(Resource.Id.enable_quickunlock);
App.getDB().QuickUnlockEnabled = cbQuickUnlock.Checked;
App.getDB().QuickUnlockKeyLength = int.Parse(prefs.GetString(GetString(Resource.String.QuickUnlockLength_key), GetString(Resource.String.QuickUnlockLength_default)));
Handler handler = new Handler();
LoadDB task = new LoadDB(App.getDB(), this, mIoConnection, pass, key, new AfterLoad(handler, this));
ProgressTask pt = new ProgressTask(this, task, Resource.String.loading_database);
pt.run();
};
/*CheckBox checkBox = (CheckBox) FindViewById(Resource.Id.show_password);
// Show or hide password
checkBox.CheckedChange += delegate(object sender, CompoundButton.CheckedChangeEventArgs e) {
TextView password = (TextView) FindViewById(Resource.Id.password);
if ( e.IsChecked ) {
password.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
} else {
password.InputType = InputTypes.ClassText | InputTypes.TextVariationPassword;
}
};
*/
ImageButton btnTogglePassword = (ImageButton)FindViewById(Resource.Id.toggle_password);
btnTogglePassword.Click += (object sender, EventArgs e) => {
mShowPassword = !mShowPassword;
TextView password = (TextView)FindViewById(Resource.Id.password);
if (mShowPassword)
{
password.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
} else
{
password.InputType = InputTypes.ClassText | InputTypes.TextVariationPassword;
}
};
CheckBox defaultCheck = (CheckBox)FindViewById(Resource.Id.default_database);
///Don't allow the current file to be the default if we don't have stored credentials
if ((mIoConnection.IsLocalFile() == false) && (mIoConnection.CredSaveMode != IOCredSaveMode.SaveCred))
{
defaultCheck.Enabled = false;
} else
{
defaultCheck.Enabled = true;
}
defaultCheck.CheckedChange += (object sender, CompoundButton.CheckedChangeEventArgs e) =>
{
String newDefaultFileName;
if (e.IsChecked)
{
newDefaultFileName = mIoConnection.Path;
} else
{
newDefaultFileName = "";
}
ISharedPreferencesEditor editor = prefs.Edit();
editor.PutString(KEY_DEFAULT_FILENAME, newDefaultFileName);
EditorCompat.apply(editor);
};
ImageButton browse = (ImageButton)FindViewById(Resource.Id.browse_button);
browse.Click += (object sender, EventArgs evt) =>
{
if (Interaction.isIntentAvailable(this, Intents.FILE_BROWSE))
{
Intent intent = new Intent(Intents.FILE_BROWSE);
if (!String.IsNullOrEmpty(mIoConnection.Path))
{
File keyfile = new File(mIoConnection.Path);
File parent = keyfile.ParentFile;
if (parent != null)
{
intent.SetData(Android.Net.Uri.Parse("file://" + parent.AbsolutePath));
}
}
try
{
StartActivityForResult(intent, Intents.REQUEST_CODE_FILE_BROWSE);
} catch (ActivityNotFoundException)
{
BrowserDialog diag = new BrowserDialog(this);
diag.Show();
}
} else
{
BrowserDialog diag = new BrowserDialog(this);
diag.Show();
}
};
retrieveSettings();
}
protected override void OnResume() {
base.OnResume();
// If the application was shutdown make sure to clear the password field, if it
// was saved in the instance state
if (App.isShutdown()) {
lockDatabase();
}
// Clear the shutdown flag
App.clearShutdown();
if (startedWithActivityResult)
return;
if (App.getDB().Loaded && (App.getDB().mIoc != null)
&& (mIoConnection != null) && (App.getDB().mIoc.GetDisplayName() == mIoConnection.GetDisplayName()))
{
if (App.getDB().Locked == false)
{
LaunchNextActivity();
}
else
{
tryStartQuickUnlock();
}
}
}
private void retrieveSettings() {
String defaultFilename = prefs.GetString(KEY_DEFAULT_FILENAME, "");
if (!String.IsNullOrEmpty(mIoConnection.Path) && mIoConnection.Path.Equals(defaultFilename)) {
CheckBox checkbox = (CheckBox) FindViewById(Resource.Id.default_database);
checkbox.Checked = true;
}
CheckBox cbQuickUnlock = (CheckBox)FindViewById(Resource.Id.enable_quickunlock);
cbQuickUnlock.Checked = prefs.GetBoolean(GetString(Resource.String.QuickUnlockDefaultEnabled_key), true);
}
private String getKeyFile(String filename) {
if ( mRememberKeyfile ) {
FileDbHelper dbHelp = App.fileDbHelper;
String keyfile = dbHelp.getFileByName(filename);
return keyfile;
} else {
return "";
}
}
private void populateView() {
setEditText(Resource.Id.filename, mIoConnection.GetDisplayName());
setEditText(Resource.Id.pass_keyfile, mKeyFile);
}
/*
private void errorMessage(CharSequence text)
{
Toast.MakeText(this, text, ToastLength.Long).Show();
}
*/
private void errorMessage(int resId)
{
Toast.MakeText(this, resId, ToastLength.Long).Show();
}
private String GetEditText(int resId) {
return Util.getEditText(this, resId);
}
private void setEditText(int resId, String str) {
TextView te = (TextView) FindViewById(resId);
//assert(te == null);
if (te != null) {
te.Text = str;
}
}
public override bool OnCreateOptionsMenu(IMenu menu) {
base.OnCreateOptionsMenu(menu);
MenuInflater inflate = MenuInflater;
inflate.Inflate(Resource.Menu.password, menu);
return true;
}
public override bool OnOptionsItemSelected(IMenuItem item) {
switch ( item.ItemId ) {
case Resource.Id.menu_about:
AboutDialog dialog = new AboutDialog(this);
dialog.Show();
return true;
case Resource.Id.menu_app_settings:
AppSettingsActivity.Launch(this);
return true;
}
return base.OnOptionsItemSelected(item);
}
private class AfterLoad : OnFinish {
PasswordActivity act;
public AfterLoad(Handler handler, PasswordActivity act):base(handler) {
this.act = act;
}
public override void run() {
if ( mSuccess ) {
act.StartQuickUnlockForegroundService();
act.LaunchNextActivity();
} else {
displayMessage(act);
}
}
}
}
}

View File

@@ -0,0 +1,87 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Java.Lang;
namespace keepass2android
{
public class ProgressTask {
private Context mCtx;
private Handler mHandler;
private RunnableOnFinish mTask;
private ProgressDialog mPd;
public ProgressTask(Context ctx, RunnableOnFinish task, int messageId) {
mCtx = ctx;
mTask = task;
mHandler = new Handler();
// Show process dialog
mPd = new ProgressDialog(mCtx);
mPd.SetTitle(ctx.GetText(Resource.String.progress_title));
mPd.SetMessage(ctx.GetText(messageId));
// Set code to run when this is finished
mTask.setStatus(new UpdateStatus(ctx, mHandler, mPd));
mTask.mFinish = new AfterTask(task.mFinish, mHandler, mPd);
}
public void run() {
// Show process dialog
mPd.Show();
// Start Thread to Run task
Thread t = new Thread(mTask.run);
t.Start();
}
private class AfterTask : OnFinish {
ProgressDialog mPd;
public AfterTask (OnFinish finish, Handler handler, ProgressDialog pd): base(finish, handler)
{
mPd = pd;
}
public override void run() {
base.run();
// Remove the progress dialog
mHandler.Post(delegate() {mPd.Dismiss();});
}
}
}
}

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="0.5 beta" package="keepass2android.keepass2android" android:installLocation="preferExternal">
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="14" />
<application android:label="keepass2android" android:icon="@drawable/ic_launcher"></application>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

View File

@@ -0,0 +1,44 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Reflection;
using System.Runtime.CompilerServices;
using Android.App;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("keepass2android")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("Philipp Crocoll")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.0")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View File

@@ -0,0 +1,47 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using KeePassLib;
namespace keepass2android
{
class PwGroupEqualityFromIdComparer: IEqualityComparer<PwGroup>
{
#region IEqualityComparer implementation
public bool Equals (PwGroup x, PwGroup y)
{
return x.Uuid.EqualsValue(y.Uuid);
}
public int GetHashCode (PwGroup obj)
{
return obj.Uuid.ToHexString().GetHashCode();
}
#endregion
}
}

View File

@@ -0,0 +1,158 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Preferences;
using KeePassLib;
using keepass2android.view;
namespace keepass2android
{
public class PwGroupListAdapter : BaseAdapter
{
private GroupBaseActivity mAct;
private PwGroup mGroup;
private List<PwGroup> groupsForViewing;
private List<PwEntry> entriesForViewing;
private ISharedPreferences prefs;
public PwGroupListAdapter(GroupBaseActivity act, PwGroup group) {
mAct = act;
mGroup = group;
prefs = PreferenceManager.GetDefaultSharedPreferences(act);
filterAndSort();
}
public override void NotifyDataSetChanged() {
base.NotifyDataSetChanged();
filterAndSort();
}
public override void NotifyDataSetInvalidated() {
base.NotifyDataSetInvalidated();
filterAndSort();
}
private void filterAndSort() {
entriesForViewing = new List<PwEntry>();
foreach (PwEntry entry in mGroup.Entries)
{
entriesForViewing.Add(entry);
}
bool sortLists = prefs.GetBoolean(mAct.GetString(Resource.String.sort_key), mAct.Resources.GetBoolean(Resource.Boolean.sort_default));
if ( sortLists )
{
groupsForViewing = new List<PwGroup>(mGroup.Groups);
groupsForViewing.Sort( (PwGroup x,PwGroup y) => { return String.Compare (x.Name, y.Name, true); });
entriesForViewing.Sort( (PwEntry x, PwEntry y) =>
{
String nameX = x.Strings.ReadSafe(PwDefs.TitleField);
String nameY = y.Strings.ReadSafe(PwDefs.TitleField);
if (nameX.ToLower() != nameY.ToLower())
return String.Compare (nameX,nameY,true);
else
return x.CreationTime.CompareTo(y.CreationTime);
}
);
} else {
groupsForViewing = new List<PwGroup>(mGroup.Groups);
}
}
public override int Count
{
get{
return groupsForViewing.Count + entriesForViewing.Count;
}
}
public override Java.Lang.Object GetItem(int position) {
return position;
}
public override long GetItemId(int position) {
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent) {
int size = groupsForViewing.Count;
if ( position < size ) {
return createGroupView(position, convertView);
} else {
return createEntryView(position - size, convertView);
}
}
private View createGroupView(int position, View convertView) {
PwGroup g = groupsForViewing[position];
PwGroupView gv;
if (convertView == null || !(convertView is PwGroupView)) {
gv = PwGroupView.getInstance(mAct, g);
}
else {
gv = (PwGroupView) convertView;
gv.convertView(g);
}
return gv;
}
private PwEntryView createEntryView(int position, View convertView) {
PwEntry entry = entriesForViewing[position];
PwEntryView ev;
if (convertView == null || !(convertView is PwEntryView)) {
ev = PwEntryView.getInstance(mAct, entry, position);
}
else {
ev = (PwEntryView) convertView;
ev.convertView(entry, position);
}
return ev;
}
}
}

View File

@@ -0,0 +1,49 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using KeePassLib;
namespace keepass2android
{
class PwUuidEqualityComparer: IEqualityComparer<PwUuid>
{
#region IEqualityComparer implementation
public bool Equals (PwUuid x, PwUuid y)
{
return x.EqualsValue(y);
}
public int GetHashCode (PwUuid obj)
{
return obj.ToHexString().GetHashCode();
}
#endregion
}
}

View File

@@ -0,0 +1,116 @@
/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Content.PM;
using KeePassLib.Keys;
using Android.Preferences;
using Android.Views.InputMethods;
using KeePassLib.Serialization;
namespace keepass2android
{
[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden, Theme="@style/Base")]
public class QuickUnlock : LifecycleDebugActivity
{
IOConnectionInfo mIoc;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
Intent i = Intent;
mIoc = App.getDB().mIoc;
if (mIoc == null)
{
Finish();
return;
}
SetContentView(Resource.Layout.QuickUnlock);
((TextView)FindViewById(Resource.Id.qu_filename)).Text = mIoc.GetDisplayName();
TextView txtLabel = (TextView)FindViewById(Resource.Id.QuickUnlock_label);
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
int quickUnlockLength = App.getDB().QuickUnlockKeyLength;
txtLabel.Text = GetString(Resource.String.QuickUnlock_label, new Java.Lang.Object[]{quickUnlockLength});
EditText pwd= (EditText)FindViewById(Resource.Id.QuickUnlock_password);
pwd.SetEms(quickUnlockLength);
pwd.PostDelayed(() => {
InputMethodManager keyboard = (InputMethodManager)GetSystemService(Context.InputMethodService);
keyboard.ShowSoftInput(pwd, 0);
}, 50);
SetResult(KeePass.EXIT_CHANGE_DB);
Button btnUnlock = (Button)FindViewById(Resource.Id.QuickUnlock_button);
btnUnlock.Click += (object sender, EventArgs e) =>
{
KcpPassword kcpPassword = (KcpPassword)App.getDB().pm.MasterKey.GetUserKey(typeof(KcpPassword));
String password = kcpPassword.Password.ReadString();
String expectedPasswordPart = password.Substring(Math.Max(0,password.Length-quickUnlockLength),Math.Min(password.Length, quickUnlockLength));
if (pwd.Text == expectedPasswordPart)
{
SetResult(KeePass.EXIT_QUICK_UNLOCK);
}
else
{
SetResult(KeePass.EXIT_FORCE_LOCK);
Toast.MakeText(this, GetString(Resource.String.QuickUnlock_fail), ToastLength.Long).Show();
}
Finish();
};
Button btnLock = (Button)FindViewById(Resource.Id.QuickUnlock_buttonLock);
btnLock.Click += (object sender, EventArgs e) =>
{
SetResult(KeePass.EXIT_FORCE_LOCK_AND_CHANGE_DB);
Finish();
};
}
protected override void OnResume()
{
base.OnResume();
if ( ! App.getDB().Loaded ) {
SetResult(KeePass.EXIT_CHANGE_DB);
Finish();
return;
}
}
}
}

View File

@@ -0,0 +1,44 @@
Images, layout descriptions, binary blobs and string dictionaries can be included
in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
For example, a sample Android app that contains a user interface layout (main.axml),
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
drawable/
icon.png
layout/
main.axml
values/
strings.xml
In order to get the build system to recognize Android resources, set the build action to
"AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
the build system will package the resources for distribution and generate a class called "R"
(this is an Android convention) that contains the tokens for each one of the resources
included. For example, for the above Resources layout, this is what the R class would expose:
public class R {
public class drawable {
public const int icon = 0x123;
}
public class layout {
public const int main = 0x456;
}
public class strings {
public const int first_string = 0xabc;
public const int second_string = 0xbcd;
}
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
to reference the layout/main.axml file, or R.Strings.first_string to reference the first
string in the dictionary file values/strings.xml.

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

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