First working version of KP2A Keyboard, but some features still missing

This commit is contained in:
PhilippC 2013-04-06 07:15:08 +02:00
parent 144f3d1e2c
commit dd6b376abf
50 changed files with 2364 additions and 1712 deletions

21
.gitignore vendored
View File

@ -4,3 +4,24 @@
/src/KeePassLib2Android/bin
/src/KeePass.userprefs
/src/keepass2android/Properties/AndroidManifest.xml
/src/java/kbbridge/bin/AndroidManifest.xml
/src/java/kbbridge/bin/R.txt
/src/java/kbbridge/bin/classes/keepass2android/kbbridge/BuildConfig.class
/src/java/kbbridge/bin/classes/keepass2android/kbbridge/KeyboardData.class
/src/java/kbbridge/bin/classes/keepass2android/kbbridge/KeyboardDataBuilder.class
/src/java/kbbridge/bin/classes/keepass2android/kbbridge/R$attr.class
/src/java/kbbridge/bin/classes/keepass2android/kbbridge/R$drawable.class
/src/java/kbbridge/bin/classes/keepass2android/kbbridge/R$string.class
/src/java/kbbridge/bin/classes/keepass2android/kbbridge/R$style.class
/src/java/kbbridge/bin/classes/keepass2android/kbbridge/R.class
/src/java/kbbridge/bin/kp2asoftkeyboardbridge.jar
/src/java/kbbridge/bin/res/drawable-hdpi/ic_launcher.png
/src/java/kbbridge/bin/res/drawable-mdpi/ic_launcher.png
/src/java/kbbridge/bin/res/drawable-xhdpi/ic_launcher.png
/src/java/kbbridge/libs/android-support-v4.jar
/src/java/KP2ASoftKeyboard/bin
/src/java/KP2ASoftKeyboard/gen
/src/java/KP2ASoftKeyboard/projectzip
/src/java/KP2ASoftKeyboard/createProjectZip.bat

View File

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

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{4F9D8890-82EE-4A3B-8E98-61B00B5AADAA}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{10368E6C-D01B-4462-8E8B-01FC667A7035};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<RootNamespace>KP2AKeyboard</RootNamespace>
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
<AssemblyName>KP2AKeyboard</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>True</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>False</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<WarningLevel>4</WarningLevel>
<ConsolePause>False</ConsolePause>
<AndroidLinkMode>None</AndroidLinkMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>True</Optimize>
<OutputPath>bin\Release</OutputPath>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<ConsolePause>False</ConsolePause>
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Mono.Android" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Additions\AboutAdditions.txt" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
<ItemGroup>
<TransformFile Include="Transforms\EnumFields.xml" />
<TransformFile Include="Transforms\EnumMethods.xml" />
<TransformFile Include="Transforms\Metadata.xml" />
</ItemGroup>
<ItemGroup>
<LibraryProjectZip Include="..\java\KP2ASoftKeyboard\project.zip">
<Link>project.zip</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</LibraryProjectZip>
</ItemGroup>
</Project>

View File

@ -0,0 +1,28 @@
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("KP2AKeyboard")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("Philipp")]
[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,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.

View File

@ -0,0 +1,42 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
// Laufzeitversion:4.0.30319.296
//
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
// der Code erneut generiert wird.
// </auto-generated>
//------------------------------------------------------------------------------
[assembly: Android.Runtime.ResourceDesignerAttribute("KP2AKeyboard.Resource", IsApplication=false)]
namespace KP2AKeyboard
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("Novell.MonoDroid.Build.Tasks", "1.0.0.0")]
public partial class Resource
{
public partial class Attribute
{
private Attribute()
{
}
}
public partial class String
{
// aapt resource value: 0x7f020000
public static int library_name = 2130837504;
private String()
{
}
}
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="library_name">KP2AKeyboard</string>
</resources>

View File

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

View File

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

View File

@ -0,0 +1,9 @@
<metadata>
<!--
This sample removes the class: android.support.v4.content.AsyncTaskLoader.LoadTask:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='AsyncTaskLoader.LoadTask']" />
This sample removes the method: android.support.v4.content.CursorLoader.loadInBackground:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='CursorLoader']/method[@name='loadInBackground']" />
-->
</metadata>

View File

@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "keepass2android", "keepass2
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "kp2akeytransform", "kp2akeytransform\kp2akeytransform.csproj", "{A57B3ACE-5634-469A-88C4-858BB409F356}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kp2aKeyboardBinding", "Kp2aKeyboardBinding\Kp2aKeyboardBinding.csproj", "{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -74,6 +76,24 @@ Global
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|x64.Build.0 = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Debug|Win32.ActiveCfg = Debug|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Debug|Win32.Build.0 = Debug|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Debug|x64.ActiveCfg = Debug|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Debug|x64.Build.0 = Debug|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|Any CPU.Build.0 = Release|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|Win32.ActiveCfg = Release|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|Win32.Build.0 = Release|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|x64.ActiveCfg = Release|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|x64.Build.0 = Release|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.ActiveCfg = Debug|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution

View File

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

View File

@ -0,0 +1,37 @@
This directory is for Android .jars.
There are 3 types of jars that are supported:
== Input Jar and Embedded Jar ==
This is the jar that bindings should be generated for.
For example, if you were binding the Google Maps library, this would
be Google's "maps.jar".
The difference between EmbeddedJar and InputJar is, EmbeddedJar is to be
embedded in the resulting dll as EmbeddedResource, while InputJar is not.
There are couple of reasons you wouldn't like to embed the target jar
in your dll (the ones that could be internally loaded by <uses-library>
feature e.g. maps.jar, or you cannot embed jars that are under some
proprietary license).
Set the build action for these jars in the properties page to "InputJar".
== Reference Jar and Embedded Reference Jar ==
These are jars that are referenced by the input jar. C# bindings will
not be created for these jars. These jars will be used to resolve
types used by the input jar.
NOTE: Do not add "android.jar" as a reference jar. It will be added automatically
based on the Target Framework selected.
Set the build action for these jars in the properties page to "ReferenceJar".
"EmbeddedJar" works like "ReferenceJar", but like "EmbeddedJar", it is
embedded in your dll. But at application build time, they are not included
in the final apk, like ReferenceJar files.

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{10368E6C-D01B-4462-8E8B-01FC667A7035};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<RootNamespace>Kp2aKeyboardBinding</RootNamespace>
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
<AssemblyName>Kp2aKeyboardBinding</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>True</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>False</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>False</ConsolePause>
<AndroidLinkMode>None</AndroidLinkMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>True</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<ConsolePause>False</ConsolePause>
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Mono.Android" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Additions\AboutAdditions.txt" />
<None Include="Jars\AboutJars.txt" />
</ItemGroup>
<ItemGroup>
<TransformFile Include="Transforms\EnumFields.xml" />
<TransformFile Include="Transforms\EnumMethods.xml" />
<TransformFile Include="Transforms\Metadata.xml" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Novell\Xamarin.Android.Bindings.targets" />
<ItemGroup>
<LibraryProjectZip Include="..\java\KP2ASoftKeyboard\project.zip">
<Link>project.zip</Link>
</LibraryProjectZip>
</ItemGroup>
</Project>

View File

@ -0,0 +1,28 @@
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("Kp2aKeyboardBinding")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("Philipp")]
[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,14 @@
<enum-field-mappings>
<!--
This example converts the constants Fragment_id, Fragment_name,
and Fragment_tag from android.support.v4.app.FragmentActivity.FragmentTag
to an enum called Android.Support.V4.App.FragmentTagType with values
Id, Name, and Tag.
<type enum-type="Android\Support\V4\App\FragmentTagType" java-class="android/support/v4/app/FragmentActivity$FragmentTag">
<member enum="Id" java="Fragment_id" value="1" />
<member enum="Name" java="Fragment_name" value="0" />
<member enum="Tag" java="Fragment_tag" value="2" />
</type>
-->
</enum-field-mappings>

View File

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

View File

@ -0,0 +1,9 @@
<metadata>
<!--
This sample removes the class: android.support.v4.content.AsyncTaskLoader.LoadTask:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='AsyncTaskLoader.LoadTask']" />
This sample removes the method: android.support.v4.content.CursorLoader.loadInBackground:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='CursorLoader']/method[@name='loadInBackground']" />
-->
</metadata>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -1,6 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="keepass2android.softkeyboard">
<uses-sdk android:targetSdkVersion="14" android:minSdkVersion="11"/>
package="keepass2android.softkeyboard" android:versionCode="1">
<uses-sdk android:targetSdkVersion="14" android:minSdkVersion="8"/>
<supports-screens
android:anyDensity="true"
android:largeScreens="true"

View File

@ -12,3 +12,4 @@
# Project target.
target=android-14
android.library=true

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 B

View File

@ -24,6 +24,9 @@
<!-- Symbols that are commonly considered word separators in this language -->
<string name="word_separators">\u0020.,;:!?\n()[]*&amp;@{}/&lt;&gt;_+=|&quot;</string>
<string name="change_entry">Select another entry</string>
<string name="open_entry">Select entry</string>
<!-- Labels on soft keys -->
<string name="label_go_key">Go</string>
<string name="label_next_key">Next</string>

View File

@ -68,8 +68,10 @@
</Row>
<Row android:rowEdgeFlags="bottom">
<Key android:codes="-101" android:keyIcon="@drawable/sym_keyboard_done"
android:keyWidth="20%p" android:keyEdgeFlags="left"/>
<Key android:codes="-101" android:keyIcon="@drawable/sym_keyboard_kp2a"
android:keyWidth="15%p" android:keyEdgeFlags="left"/>
<Key android:codes="-102" android:keyIcon="@drawable/sym_keyboard"
android:keyWidth="15%p"/>
<Key android:codes="-2" android:keyLabel="123" android:keyWidth="15%p"/>
<Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
android:keyWidth="30%p" android:isRepeatable="true"/>

View File

@ -0,0 +1,12 @@
package keepass2android.kbbridge;
import java.util.HashMap;
public class KeyboardData {
public static HashMap<String, String> availableFields = new HashMap<String, String>();
public static String entryName;
public static void clear()
{
availableFields.clear();
}
}

View File

@ -17,10 +17,14 @@
package keepass2android.softkeyboard;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.provider.Settings;
import android.text.InputType;
import android.view.KeyEvent;
import android.view.View;
@ -33,19 +37,20 @@ import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import keepass2android.softkeyboard.R;
/**
* Example of writing an input method for a soft keyboard. This code is
* focused on simplicity over completeness, so it should in no way be considered
* to be a complete soft keyboard implementation. Its purpose is to provide
* a basic example for how you would get started writing an input method, to
* be fleshed out as appropriate.
* Example of writing an input method for a soft keyboard. This code is focused
* on simplicity over completeness, so it should in no way be considered to be a
* complete soft keyboard implementation. Its purpose is to provide a basic
* example for how you would get started writing an input method, to be fleshed
* out as appropriate.
*/
public class KP2AKeyboard extends InputMethodService
implements KeyboardView.OnKeyboardActionListener {
public class KP2AKeyboard extends InputMethodService implements
KeyboardView.OnKeyboardActionListener {
static final boolean DEBUG = false;
private InputMethodManager mInputMethodManager;
@ -71,26 +76,30 @@ public class KP2AKeyboard extends InputMethodService
private String mWordSeparators;
/**
* Main initialization of the input method component. Be sure to call
* to super class.
* Main initialization of the input method component. Be sure to call to
* super class.
*/
@Override public void onCreate() {
@Override
public void onCreate() {
super.onCreate();
mInputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
mWordSeparators = getResources().getString(R.string.word_separators);
}
/**
* This is the point where you can do all of your UI initialization. It
* is called after creation and any configuration change.
* This is the point where you can do all of your UI initialization. It is
* called after creation and any configuration change.
*/
@Override public void onInitializeInterface() {
@Override
public void onInitializeInterface() {
if (mQwertyKeyboard != null) {
// Configuration changes can happen after the keyboard gets recreated,
// Configuration changes can happen after the keyboard gets
// recreated,
// so we need to be able to re-build the keyboards if the available
// space has changed.
int displayWidth = getMaxWidth();
if (displayWidth == mLastDisplayWidth) return;
if (displayWidth == mLastDisplayWidth)
return;
mLastDisplayWidth = displayWidth;
}
mQwertyKeyboard = new LatinKeyboard(this, R.xml.qwerty);
@ -99,12 +108,13 @@ public class KP2AKeyboard extends InputMethodService
}
/**
* Called by the framework when your view for creating input needs to
* be generated. This will be called the first time your input method
* is displayed, and every time it needs to be re-created such as due to
* a configuration change.
* Called by the framework when your view for creating input needs to be
* generated. This will be called the first time your input method is
* displayed, and every time it needs to be re-created such as due to a
* configuration change.
*/
@Override public View onCreateInputView() {
@Override
public View onCreateInputView() {
mInputView = (LatinKeyboardView) getLayoutInflater().inflate(
R.layout.input, null);
mInputView.setOnKeyboardActionListener(this);
@ -113,10 +123,11 @@ public class KP2AKeyboard extends InputMethodService
}
/**
* Called by the framework when your view for showing candidates needs to
* be generated, like {@link #onCreateInputView}.
* Called by the framework when your view for showing candidates needs to be
* generated, like {@link #onCreateInputView}.
*/
@Override public View onCreateCandidatesView() {
@Override
public View onCreateCandidatesView() {
mCandidateView = new CandidateView(this);
mCandidateView.setService(this);
return mCandidateView;
@ -124,15 +135,17 @@ public class KP2AKeyboard extends InputMethodService
/**
* This is the main point where we do our initialization of the input method
* to begin operating on an application. At this point we have been
* bound to the client, and are now receiving all of the detailed information
* about the target of our edits.
* to begin operating on an application. At this point we have been bound to
* the client, and are now receiving all of the detailed information about
* the target of our edits.
*/
@Override public void onStartInput(EditorInfo attribute, boolean restarting) {
@Override
public void onStartInput(EditorInfo attribute, boolean restarting) {
super.onStartInput(attribute, restarting);
// Reset our state. We want to do this even if restarting, because
// the underlying state of the text editor could have changed in any way.
// the underlying state of the text editor could have changed in any
// way.
mComposing.setLength(0);
updateCandidates();
@ -172,8 +185,8 @@ public class KP2AKeyboard extends InputMethodService
// We now look for a few special variations of text that will
// modify our behavior.
int variation = attribute.inputType & InputType.TYPE_MASK_VARIATION;
if (variation == InputType.TYPE_TEXT_VARIATION_PASSWORD ||
variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
if (variation == InputType.TYPE_TEXT_VARIATION_PASSWORD
|| variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
// Do not display predictions / what the user is typing
// when they are entering a password.
mPredictionOn = false;
@ -216,10 +229,11 @@ public class KP2AKeyboard extends InputMethodService
}
/**
* This is called when the user is done editing a field. We can use
* this to reset our state.
* This is called when the user is done editing a field. We can use this to
* reset our state.
*/
@Override public void onFinishInput() {
@Override
public void onFinishInput() {
super.onFinishInput();
// Clear current composing text and candidates.
@ -238,12 +252,14 @@ public class KP2AKeyboard extends InputMethodService
}
}
@Override public void onStartInputView(EditorInfo attribute, boolean restarting) {
@Override
public void onStartInputView(EditorInfo attribute, boolean restarting) {
super.onStartInputView(attribute, restarting);
// Apply the selected keyboard to the input view.
mInputView.setKeyboard(mCurKeyboard);
mInputView.closing();
//final InputMethodSubtype subtype = mInputMethodManager.getCurrentInputMethodSubtype();
// final InputMethodSubtype subtype =
// mInputMethodManager.getCurrentInputMethodSubtype();
// mInputView.setSubtypeOnSpaceKey(subtype);
}
@ -255,16 +271,17 @@ public class KP2AKeyboard extends InputMethodService
/**
* Deal with the editor reporting movement of its cursor.
*/
@Override public void onUpdateSelection(int oldSelStart, int oldSelEnd,
int newSelStart, int newSelEnd,
int candidatesStart, int candidatesEnd) {
@Override
public void onUpdateSelection(int oldSelStart, int oldSelEnd,
int newSelStart, int newSelEnd, int candidatesStart,
int candidatesEnd) {
super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
candidatesStart, candidatesEnd);
// If the current selection in the text view changes, we should
// clear whatever candidate text we have.
if (mComposing.length() > 0 && (newSelStart != candidatesEnd
|| newSelEnd != candidatesEnd)) {
if (mComposing.length() > 0
&& (newSelStart != candidatesEnd || newSelEnd != candidatesEnd)) {
mComposing.setLength(0);
updateCandidates();
InputConnection ic = getCurrentInputConnection();
@ -275,12 +292,13 @@ public class KP2AKeyboard extends InputMethodService
}
/**
* This tells us about completions that the editor has determined based
* on the current text in it. We want to use this in fullscreen mode
* to show the completions ourself, since the editor can not be seen
* in that situation.
* This tells us about completions that the editor has determined based on
* the current text in it. We want to use this in fullscreen mode to show
* the completions ourself, since the editor can not be seen in that
* situation.
*/
@Override public void onDisplayCompletions(CompletionInfo[] completions) {
@Override
public void onDisplayCompletions(CompletionInfo[] completions) {
if (mCompletionOn) {
mCompletions = completions;
if (completions == null) {
@ -291,19 +309,20 @@ public class KP2AKeyboard extends InputMethodService
List<String> stringList = new ArrayList<String>();
for (int i = 0; i < completions.length; i++) {
CompletionInfo ci = completions[i];
if (ci != null) stringList.add(ci.getText().toString());
if (ci != null)
stringList.add(ci.getText().toString());
}
setSuggestions(stringList, true, true);
}
}
/**
* Use this to monitor key events being delivered to the application.
* We get first crack at them, and can either resume them or let them
* continue to the app.
* Use this to monitor key events being delivered to the application. We get
* first crack at them, and can either resume them or let them continue to
* the app.
*/
@Override public boolean onKeyDown(int keyCode, KeyEvent event) {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
// The InputMethodService already takes care of the back
@ -338,7 +357,6 @@ public class KP2AKeyboard extends InputMethodService
return super.onKeyDown(keyCode, event);
}
/**
* Helper function to commit any text being composed in to the editor.
*/
@ -355,12 +373,13 @@ public class KP2AKeyboard extends InputMethodService
* editor state.
*/
private void updateShiftKeyState(EditorInfo attr) {
if (attr != null
&& mInputView != null && mQwertyKeyboard == mInputView.getKeyboard()) {
if (attr != null && mInputView != null
&& mQwertyKeyboard == mInputView.getKeyboard()) {
int caps = 0;
EditorInfo ei = getCurrentInputEditorInfo();
if (ei != null && ei.inputType != InputType.TYPE_NULL) {
caps = getCurrentInputConnection().getCursorCapsMode(attr.inputType);
caps = getCurrentInputConnection().getCursorCapsMode(
attr.inputType);
}
mInputView.setShifted(mCapsLock || caps != 0);
}
@ -399,7 +418,8 @@ public class KP2AKeyboard extends InputMethodService
if (keyCode >= '0' && keyCode <= '9') {
keyDownUp(keyCode - '0' + KeyEvent.KEYCODE_0);
} else {
getCurrentInputConnection().commitText(String.valueOf((char) keyCode), 1);
getCurrentInputConnection().commitText(
String.valueOf((char) keyCode), 1);
}
break;
}
@ -416,34 +436,76 @@ public class KP2AKeyboard extends InputMethodService
sendKey(primaryCode);
updateShiftKeyState(getCurrentInputEditorInfo());
} else if (primaryCode == Keyboard.KEYCODE_DELETE) {
android.util.Log.d("DEBUG", "DELETE");
handleBackspace();
} else if (primaryCode == Keyboard.KEYCODE_SHIFT) {
android.util.Log.d("DEBUG", "SHIFT");
handleShift();
} else if (primaryCode == Keyboard.KEYCODE_CANCEL) {
android.util.Log.d("DEBUG", "CANCEL");
handleClose();
return;
} else if (primaryCode == LatinKeyboardView.KEYCODE_KP2A) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final CharSequence[] items = {"Gallery Image Menu!", "hello你好", "View pattern", "Delete pattern", "Locate pattern in list view", "Row Counter (with pattern)", "Share Pattern", "Share Image"};
builder.setTitle("Keepass2Android");
String title = "Keepass2Android";
HashMap<String, String> availableFields = keepass2android.kbbridge.KeyboardData.availableFields;
final ArrayList<String> items = new ArrayList<String>();
final ArrayList<String> values = new ArrayList<String>();
for (HashMap.Entry<String, String> entry : availableFields.entrySet())
{
String key = entry.getKey();
String value = entry.getValue();
items.add(key);
values.add(value);
}
if (keepass2android.kbbridge.KeyboardData.entryName == null)
{
items.add(getString(R.string.open_entry));
values.add("");
}
else
{
title += " ("+keepass2android.kbbridge.KeyboardData.entryName+")";
items.add(getString(R.string.change_entry));
values.add("");
}
builder.setTitle(title);
// builder.setMessage("What do you want to type securely?");
builder.setItems(items, new DialogInterface.OnClickListener() {
builder.setItems(items.toArray(new CharSequence[items.size()]),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
getCurrentInputConnection().commitText(items[item],0);
if (item == 0){
if (item == items.size() - 1) {
//change entry
Intent startKp2aIntent = getPackageManager().getLaunchIntentForPackage(getApplicationContext().getPackageName());
if (startKp2aIntent != null)
{
startKp2aIntent.addCategory(Intent.CATEGORY_LAUNCHER);
startKp2aIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startKp2aIntent);
Settings.Secure.getString(
getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD
);
}
} else {
getCurrentInputConnection().commitText(
values.get(item), 0);
}
}
});
// Add the buttons
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
builder.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// User cancelled the dialog
}
});
// Set other dialog properties
// Create the AlertDialog
AlertDialog dialog = builder.create();
@ -455,12 +517,13 @@ public class KP2AKeyboard extends InputMethodService
window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
dialog.show();
} else if (primaryCode == LatinKeyboardView.KEYCODE_OPTIONS) {
// Show a menu or somethin'
} else if (primaryCode == LatinKeyboardView.KEYCODE_SELECT_IME) {
mInputMethodManager.showInputMethodPicker();
} else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE
&& mInputView != null) {
Keyboard current = mInputView.getKeyboard();
if (current == mSymbolsKeyboard || current == mSymbolsShiftedKeyboard) {
if (current == mSymbolsKeyboard
|| current == mSymbolsShiftedKeyboard) {
current = mQwertyKeyboard;
} else {
current = mSymbolsKeyboard;
@ -479,7 +542,8 @@ public class KP2AKeyboard extends InputMethodService
public void onText(CharSequence text) {
InputConnection ic = getCurrentInputConnection();
if (ic == null) return;
if (ic == null)
return;
ic.beginBatchEdit();
if (mComposing.length() > 0) {
commitTyped(ic);
@ -490,9 +554,8 @@ public class KP2AKeyboard extends InputMethodService
}
/**
* Update the list of available candidates from the current composing
* text. This will need to be filled in by however you are determining
* candidates.
* Update the list of available candidates from the current composing text.
* This will need to be filled in by however you are determining candidates.
*/
private void updateCandidates() {
if (!mCompletionOn) {
@ -514,7 +577,8 @@ public class KP2AKeyboard extends InputMethodService
setCandidatesViewShown(true);
}
if (mCandidateView != null) {
mCandidateView.setSuggestions(suggestions, completions, typedWordValid);
mCandidateView.setSuggestions(suggestions, completions,
typedWordValid);
}
}
@ -545,7 +609,6 @@ public class KP2AKeyboard extends InputMethodService
checkToggleCapsLock();
mInputView.setShifted(mCapsLock || !mInputView.isShifted());
} else if (currentKeyboard == mSymbolsKeyboard) {
mSymbolsKeyboard.setShifted(true);
mInputView.setKeyboard(mSymbolsShiftedKeyboard);

View File

@ -27,6 +27,7 @@ public class LatinKeyboardView extends KeyboardView {
static final int KEYCODE_OPTIONS = -100;
static final int KEYCODE_KP2A = -101;
static final int KEYCODE_SELECT_IME = -102;
public LatinKeyboardView(Context context, AttributeSet attrs) {
super(context, attrs);

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>KP2ASoftKeyboardBridge</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -1,17 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="keepass2android.kbbridge"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
</application>
</manifest>

View File

@ -1,6 +0,0 @@
/** Automatically generated file. DO NOT MODIFY */
package keepass2android.kbbridge;
public final class BuildConfig {
public final static boolean DEBUG = true;
}

View File

@ -1,47 +0,0 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package keepass2android.kbbridge;
public final class R {
public static final class attr {
}
public static final class drawable {
public static int ic_launcher=0x7f020000;
}
public static final class string {
public static int app_name=0x7f030000;
}
public static final class style {
/**
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
Base application theme for API 11+. This theme completely replaces
AppBaseTheme from res/values/styles.xml on API 11+ devices.
API 11 theme customizations can go here.
Base application theme for API 14+. This theme completely replaces
AppBaseTheme from BOTH res/values/styles.xml and
res/values-v11/styles.xml on API 14+ devices.
API 14 theme customizations can go here.
*/
public static int AppBaseTheme=0x7f040000;
/** Application theme.
All customizations that are NOT specific to a particular API-level can go here.
*/
public static int AppTheme=0x7f040001;
}
}

View File

@ -1,20 +0,0 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -1,15 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-14
android.library=true

View File

@ -1,5 +0,0 @@
<resources>
<string name="app_name">KP2ASoftKeyboardBridge</string>
</resources>

View File

@ -1,20 +0,0 @@
<resources>
<!--
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Light">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
</style>
</resources>

View File

@ -1,6 +0,0 @@
package keepass2android.kbbridge;
import java.util.HashMap;
public class KeyboardData {
public static HashMap<String, String> availableFields = new HashMap<String, String>();
}

View File

@ -25,6 +25,14 @@
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kdbx" />
</intent-filter>
</activity>
<service android:name="keepass2android.softkeyboard.KP2AKeyboard"
android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod" />
</intent-filter>
<meta-data android:name="android.view.im" android:resource="@xml/method" />
</service>
</application>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 896 B

View File

@ -28,6 +28,9 @@
<string name="clipboard_timeout_summary">Time before clearing clipboard after copying username or password</string>
<string name="copy_username">Select to copy username to clipboard</string>
<string name="copy_password">Select to copy password to clipboard</string>
<string name="available_through_keyboard">Entry is available through KP2A Keyboard</string>
<string name="not_possible_im_picker">Could not open dialog to select input method. Please activate keyboard manually.</string>
<string name="please_activate_keyboard">Please enable the Keepass2Android keyboard in your system settings.</string>
<string name="creating_db_key">Creating database key…</string>
<string name="current_group">Current Group</string>
<string name="current_group_root">Current Group: Root</string>

View File

@ -35,6 +35,7 @@ namespace keepass2android
public const String COPY_USERNAME = "keepass2android.copy_username";
public const String COPY_PASSWORD = "keepass2android.copy_password";
public const String CHECK_KEYBOARD = "keepass2android.check_keyboard";
public const String FILE_BROWSE = "org.openintents.action.PICK_FILE";
public const int REQUEST_CODE_FILE_BROWSE = 987321;

View File

@ -583,6 +583,8 @@
<AndroidResource Include="Resources\values-zh-rCN\strings.xml" />
<AndroidResource Include="Resources\values-zh-rTW\strings.xml" />
<AndroidResource Include="Resources\drawable\ic_launcher_gray.png" />
<AndroidResource Include="Resources\drawable-hdpi\notify_keyboard.png" />
<AndroidResource Include="Resources\drawable\notify_keyboard.png" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
<ItemGroup>
@ -644,6 +646,10 @@
<Project>{A57B3ACE-5634-469A-88C4-858BB409F356}</Project>
<Name>kp2akeytransform</Name>
</ProjectReference>
<ProjectReference Include="..\Kp2aKeyboardBinding\Kp2aKeyboardBinding.csproj">
<Project>{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}</Project>
<Name>Kp2aKeyboardBinding</Name>
</ProjectReference>
</ItemGroup>
<ProjectExtensions>
<MonoDevelop>

View File

@ -30,6 +30,7 @@ using Android.Widget;
using Android.Preferences;
using KeePassLib;
using KeePassLib.Utility;
using Android.Views.InputMethods;
namespace keepass2android
{
@ -40,6 +41,8 @@ namespace keepass2android
public const int NOTIFY_USERNAME = 1;
public const int NOTIFY_PASSWORD = 2;
public const int NOTIFY_KEYBOARD = 3;
public const int CLEAR_CLIPBOARD = 4;
public CopyToClipboardService (IntPtr javaReference, JniHandleOwnership transfer)
@ -68,7 +71,7 @@ namespace keepass2android
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
Android.Util.Log.Debug("DEBUG","Received intent to copy to clipboard");
Android.Util.Log.Debug("DEBUG","Received intent to provide access to entry");
String uuidBytes = intent.GetStringExtra(EntryActivity.KEY_ENTRY);
@ -95,7 +98,8 @@ namespace keepass2android
return StartCommandResult.NotSticky;
}
displayCopyNotifications(entry);
displayAccessNotifications(entry);
return StartCommandResult.RedeliverIntent;
}
@ -117,6 +121,7 @@ namespace keepass2android
if ( mNM != null ) {
mNM.CancelAll();
mNumElementsToWaitFor= 0;
clearKeyboard();
}
Android.Util.Log.Debug("DEBUG", "Destroyed Show-Notification-Receiver.");
@ -131,27 +136,30 @@ namespace keepass2android
PendingIntent createDeleteIntent(int requestCode)
{
Intent intent = new Intent(ACTION_NOTIFICATION_CANCELLED);
Bundle extra = new Bundle();
extra.PutInt("requestCode", requestCode);
intent.PutExtras(extra);
return PendingIntent.GetBroadcast(this, requestCode, intent, PendingIntentFlags.CancelCurrent);
}
public void displayCopyNotifications(PwEntry entry)
public void displayAccessNotifications(PwEntry entry)
{
// Notification Manager
mNM = (NotificationManager)GetSystemService(NotificationService);
mNM.CancelAll();
mNumElementsToWaitFor = 0;
clearKeyboard();
String entryName = entry.Strings.ReadSafe(PwDefs.TitleField);
if (entry.Strings.ReadSafe(PwDefs.PasswordField).Length > 0)
{
// only show notification if password is available
Notification password = GetNotification(Intents.COPY_PASSWORD, Resource.String.copy_password, entryName);
Notification password = GetNotification(Intents.COPY_PASSWORD, Resource.String.copy_password, Resource.Drawable.notify, entryName);
password.DeleteIntent = createDeleteIntent(0);
password.DeleteIntent = createDeleteIntent(NOTIFY_PASSWORD);
mNM.Notify(NOTIFY_PASSWORD, password);
mNumElementsToWaitFor++;
@ -160,12 +168,22 @@ namespace keepass2android
if (entry.Strings.ReadSafe(PwDefs.UserNameField).Length > 0)
{
// only show notification if username is available
Notification username = GetNotification(Intents.COPY_USERNAME, Resource.String.copy_username, entryName);
username.DeleteIntent = createDeleteIntent(1);
Notification username = GetNotification(Intents.COPY_USERNAME, Resource.String.copy_username, Resource.Drawable.notify, entryName);
username.DeleteIntent = createDeleteIntent(NOTIFY_USERNAME);
mNumElementsToWaitFor++;
mNM.Notify(NOTIFY_USERNAME, username);
}
//keyboard
if (makeAccessibleForKeyboard(entry))
{
// only show notification if username is available
Notification keyboard = GetNotification(Intents.CHECK_KEYBOARD, Resource.String.available_through_keyboard, Resource.Drawable.notify_keyboard, entryName);
keyboard.DeleteIntent = createDeleteIntent(NOTIFY_KEYBOARD);
mNumElementsToWaitFor++;
mNM.Notify(NOTIFY_KEYBOARD, keyboard);
}
if (mNumElementsToWaitFor == 0)
{
StopSelf();
@ -177,6 +195,7 @@ namespace keepass2android
IntentFilter filter = new IntentFilter();
filter.AddAction(Intents.COPY_USERNAME);
filter.AddAction(Intents.COPY_PASSWORD);
filter.AddAction(Intents.CHECK_KEYBOARD);
RegisterReceiver(mCopyToClipBroadcastReceiver, filter);
//register receiver to get notified when notifications are discarded in which case we can shutdown the service
@ -186,15 +205,72 @@ namespace keepass2android
RegisterReceiver(mNotificationDeletedBroadcastReceiver, deletefilter);
}
public void OnWaitElementDeleted()
bool makeAccessibleForKeyboard(PwEntry entry)
{
bool hasData = false;
Keepass2android.Kbbridge.KeyboardDataBuilder kbdataBuilder = new Keepass2android.Kbbridge.KeyboardDataBuilder();
String[] keys = {PwDefs.UserNameField,
PwDefs.PasswordField,
PwDefs.UrlField,
PwDefs.NotesField,
PwDefs.TitleField
};
int[] resIds = {Resource.String.entry_user_name,
Resource.String.entry_password,
Resource.String.entry_url,
Resource.String.entry_comment,
Resource.String.entry_title };
//add standard fields:
int i=0;
foreach (string key in keys)
{
String value = entry.Strings.ReadSafe(key);
if (value.Length > 0)
{
kbdataBuilder.AddPair(GetString(resIds[i]), value);
hasData = true;
}
i++;
}
//add additional fields:
foreach (var pair in entry.Strings)
{
String key = pair.Key;
if (!PwDefs.IsStandardField(key)) {
kbdataBuilder.AddPair(pair.Key, entry.Strings.ReadSafe(pair.Key));
}
}
kbdataBuilder.Commit();
Keepass2android.Kbbridge.KeyboardData.EntryName = entry.Strings.ReadSafe(PwDefs.TitleField);
return hasData;
}
public void OnWaitElementDeleted(int itemId)
{
mNumElementsToWaitFor--;
if (mNumElementsToWaitFor <= 0)
{
StopSelf();
}
if (itemId == NOTIFY_KEYBOARD)
{
//keyboard notification was deleted -> clear entries in keyboard
clearKeyboard();
}
}
void clearKeyboard()
{
Keepass2android.Kbbridge.KeyboardData.AvailableFields.Clear();
Keepass2android.Kbbridge.KeyboardData.EntryName = null;
}
private Timer mTimer = new Timer();
@ -227,7 +303,7 @@ namespace keepass2android
public override void Run() {
String currentClip = Util.getClipboard(mService);
handler.Post( () => { mService.OnWaitElementDeleted(); });
handler.Post( () => { mService.OnWaitElementDeleted(CLEAR_CLIPBOARD); });
if ( currentClip.Equals(mClearText) ) {
Util.copyToClipboard(mService, "");
handler.Post( () => {
@ -241,7 +317,7 @@ namespace keepass2android
// Setup to allow the toast to happen in the foreground
Handler uiThreadCallback = new Handler();
private Notification GetNotification(String intentText, int descResId, String entryName) {
private Notification GetNotification(String intentText, int descResId, int drawableResId, String entryName) {
String desc = GetString(descResId);
String title = GetString(Resource.String.app_name);
@ -249,10 +325,10 @@ namespace keepass2android
title += " (" + entryName +")";
Notification notify = new Notification(Resource.Drawable.notify, desc, Java.Lang.JavaSystem.CurrentTimeMillis());
Notification notify = new Notification(drawableResId, desc, Java.Lang.JavaSystem.CurrentTimeMillis());
Intent intent = new Intent(intentText);
PendingIntent pending = PendingIntent.GetBroadcast(this, 0, intent, PendingIntentFlags.CancelCurrent);
PendingIntent pending = PendingIntent.GetBroadcast(this, descResId, intent, PendingIntentFlags.CancelCurrent);
notify.SetLatestEventInfo(this, title, desc, pending);
@ -273,19 +349,57 @@ namespace keepass2android
PwEntry mEntry;
public override void OnReceive(Context context, Intent intent) {
public override void OnReceive(Context context, Intent intent)
{
String action = intent.Action;
if ( action.Equals(Intents.COPY_USERNAME) ) {
if (action.Equals(Intents.COPY_USERNAME))
{
String username = mEntry.Strings.ReadSafe(PwDefs.UserNameField);
if ( username.Length > 0 ) {
if (username.Length > 0)
{
mService.timeoutCopyToClipboard(username);
}
} else if ( action.Equals(Intents.COPY_PASSWORD) ) {
} else if (action.Equals(Intents.COPY_PASSWORD))
{
String password = mEntry.Strings.ReadSafe(PwDefs.PasswordField);
if ( password.Length > 0 ) {
if (password.Length > 0)
{
mService.timeoutCopyToClipboard(password);
}
} else if (action.Equals(Intents.CHECK_KEYBOARD))
{
string currentIme = Android.Provider.Settings.Secure.GetString(
mService.ContentResolver,
Android.Provider.Settings.Secure.DefaultInputMethod);
string kp2aIme = mService.PackageName+"/keepass2android.softkeyboard.KP2AKeyboard";
InputMethodManager imeManager = (InputMethodManager)mService.ApplicationContext.GetSystemService(Context.InputMethodService);
if (currentIme == kp2aIme)
{
imeManager.ToggleSoftInput(ShowSoftInputFlags.Explicit, HideSoftInputFlags.None);
return;
}
IList<InputMethodInfo> inputMethodProperties = imeManager.EnabledInputMethodList;
if (!inputMethodProperties.Any(imi => imi.Id.Equals(kp2aIme)))
{
Toast.MakeText(mService, Resource.String.please_activate_keyboard, ToastLength.Long).Show();
Intent settingsIntent = new Intent(Android.Provider.Settings.ActionInputMethodSettings);
settingsIntent.SetFlags(ActivityFlags.NewTask);
mService.StartActivity(settingsIntent);
}
else
{
if (imeManager != null) {
imeManager.ShowInputMethodPicker();
} else {
Toast.MakeText(mService, Resource.String.not_possible_im_picker, ToastLength.Long).Show();
}
}
}
}
};
@ -303,7 +417,7 @@ namespace keepass2android
{
if (intent.Action == CopyToClipboardService.ACTION_NOTIFICATION_CANCELLED)
{
mService.OnWaitElementDeleted();
mService.OnWaitElementDeleted(intent.Extras.GetInt("requestCode"));
}
}
#endregion