Merge branch 'master' of C:\ph\keepass2android

This commit is contained in:
Philipp Crocoll
2017-04-11 02:26:34 +02:00
42 changed files with 1673 additions and 38 deletions

27
.gitignore vendored
View File

@@ -152,3 +152,30 @@ Thumbs.db
/src/java/PluginInputStick3/keepass2AndroidPluginSDK/build/ /src/java/PluginInputStick3/keepass2AndroidPluginSDK/build/
/src/java/KP2ASoftkeyboard_AS/.gradle/2.2.1/taskArtifacts/cache.properties /src/java/KP2ASoftkeyboard_AS/.gradle/2.2.1/taskArtifacts/cache.properties
/src/java/KP2ASoftkeyboard_AS/.gradle/2.2.1/taskArtifacts/cache.properties.lock /src/java/KP2ASoftkeyboard_AS/.gradle/2.2.1/taskArtifacts/cache.properties.lock
/src/java/JavaFileStorageTest-AS/.idea/.name
/src/java/JavaFileStorageTest-AS/.idea/compiler.xml
/src/java/JavaFileStorageTest-AS/.idea/copyright/profiles_settings.xml
/src/java/JavaFileStorageTest-AS/.idea/encodings.xml
/src/java/JavaFileStorageTest-AS/.idea/gradle.xml
/src/java/JavaFileStorageTest-AS/.idea/misc.xml
/src/java/JavaFileStorageTest-AS/.idea/modules.xml
/src/java/JavaFileStorageTest-AS/.idea/runConfigurations.xml
/src/java/Keepass2AndroidPluginSDK2/.gradle/2.2.1/taskArtifacts/cache.properties
/src/java/Keepass2AndroidPluginSDK2/.gradle/2.2.1/taskArtifacts/cache.properties.lock
/src/java/Keepass2AndroidPluginSDK2/.gradle/2.2.1/taskArtifacts/fileHashes.bin
/src/java/Keepass2AndroidPluginSDK2/.gradle/2.2.1/taskArtifacts/fileSnapshots.bin
/src/java/Keepass2AndroidPluginSDK2/.gradle/2.2.1/taskArtifacts/outputFileStates.bin
/src/java/Keepass2AndroidPluginSDK2/.gradle/2.2.1/taskArtifacts/taskArtifacts.bin
/src/java/Keepass2AndroidPluginSDK2/.idea/.name
/src/java/Keepass2AndroidPluginSDK2/.idea/compiler.xml
/src/java/Keepass2AndroidPluginSDK2/.idea/copyright/profiles_settings.xml
/src/java/Keepass2AndroidPluginSDK2/.idea/encodings.xml
/src/java/Keepass2AndroidPluginSDK2/.idea/gradle.xml
/src/java/Keepass2AndroidPluginSDK2/.idea/libraries/effects_android_23.xml
/src/java/Keepass2AndroidPluginSDK2/.idea/libraries/maps_android_23.xml
/src/java/Keepass2AndroidPluginSDK2/.idea/libraries/mockable_Google_Inc__Google_APIs_23.xml
/src/java/Keepass2AndroidPluginSDK2/.idea/libraries/usb_android_23.xml
/src/java/Keepass2AndroidPluginSDK2/.idea/misc.xml
/src/java/Keepass2AndroidPluginSDK2/.idea/modules.xml
/src/java/Keepass2AndroidPluginSDK2/.idea/runConfigurations.xml
/src/java/Keepass2AndroidPluginSDK2/.idea/workspace.xml

View File

@@ -10,6 +10,28 @@ namespace keepass2android.Io
{ {
public static class IoUtil public static class IoUtil
{ {
public static bool TryTakePersistablePermissions(ContentResolver contentResolver, Android.Net.Uri uri)
{
if ((int)Build.VERSION.SdkInt >= 19)
{
//try to take persistable permissions
try
{
Kp2aLog.Log("TakePersistableUriPermission");
var takeFlags = (ActivityFlags.GrantReadUriPermission
| ActivityFlags.GrantWriteUriPermission);
contentResolver.TakePersistableUriPermission(uri, takeFlags);
return true;
}
catch (Exception e)
{
Kp2aLog.Log(e.ToString());
}
}
return false;
}
public static bool DeleteDir(File dir, bool contentsOnly=false) public static bool DeleteDir(File dir, bool contentsOnly=false)
{ {
if (dir != null && dir.IsDirectory) if (dir != null && dir.IsDirectory)
@@ -102,5 +124,6 @@ namespace keepass2android.Io
else else
return ctx.FilesDir; return ctx.FilesDir;
} }
} }
} }

View File

@@ -47,13 +47,23 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="ModernHttpClient">
<HintPath>..\Components\modernhttpclient-2.4.2\lib\android\ModernHttpClient.dll</HintPath>
</Reference>
<Reference Include="Mono.Android" /> <Reference Include="Mono.Android" />
<Reference Include="Mono.Security" /> <Reference Include="Mono.Security" />
<Reference Include="mscorlib" /> <Reference Include="mscorlib" />
<Reference Include="OkHttp">
<HintPath>..\Components\modernhttpclient-2.4.2\lib\android\OkHttp.dll</HintPath>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="Xamarin.Insights">
<HintPath>..\packages\Xamarin.Insights.1.11.3\lib\MonoAndroid10\Xamarin.Insights.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="database\CheckDatabaseForChanges.cs" /> <Compile Include="database\CheckDatabaseForChanges.cs" />
@@ -123,6 +133,10 @@
<Compile Include="Utils\Spr\SprEngine.PickChars.cs" /> <Compile Include="Utils\Spr\SprEngine.PickChars.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj">
<Project>{48574278-4779-4b3a-a9e4-9cf1bc285d0b}</Project>
<Name>JavaFileStorageBindings</Name>
</ProjectReference>
<ProjectReference Include="..\KeePassLib2Android\KeePassLib2Android.csproj"> <ProjectReference Include="..\KeePassLib2Android\KeePassLib2Android.csproj">
<Project>{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}</Project> <Project>{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}</Project>
<Name>KeePassLib2Android</Name> <Name>KeePassLib2Android</Name>
@@ -131,6 +145,10 @@
<Project>{70D3844A-D9FA-4A64-B205-A84C6A822196}</Project> <Project>{70D3844A-D9FA-4A64-B205-A84C6A822196}</Project>
<Name>KP2AKdbLibraryBinding</Name> <Name>KP2AKdbLibraryBinding</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\netftpandroid\System.Net.FtpClient\System.Net.FtpClient.Android.csproj">
<Project>{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}</Project>
<Name>System.Net.FtpClient.Android</Name>
</ProjectReference>
<ProjectReference Include="..\TwofishCipher\TwofishCipher.csproj"> <ProjectReference Include="..\TwofishCipher\TwofishCipher.csproj">
<Project>{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}</Project> <Project>{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}</Project>
<Name>TwofishCipher</Name> <Name>TwofishCipher</Name>
@@ -139,6 +157,12 @@
<ItemGroup> <ItemGroup>
<Folder Include="Resources\" /> <Folder Include="Resources\" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<XamarinComponentReference Include="modernhttpclient">
<Visible>False</Visible>
<Version>2.4.2</Version>
</XamarinComponentReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -122,23 +122,7 @@ namespace keepass2android
{ {
if (data.Data.Scheme == "content") if (data.Data.Scheme == "content")
{ {
if ((int) Build.VERSION.SdkInt >= 19) IoUtil.TryTakePersistablePermissions(this.ContentResolver, data.Data);
{
//try to take persistable permissions
try
{
Kp2aLog.Log("TakePersistableUriPermission");
var takeFlags = data.Flags
& (ActivityFlags.GrantReadUriPermission
| ActivityFlags.GrantWriteUriPermission);
this.ContentResolver.TakePersistableUriPermission(data.Data, takeFlags);
}
catch (Exception e)
{
Kp2aLog.Log(e.ToString());
}
}
IocSelected(IOConnectionInfo.FromPath(data.DataString), requestCode); IocSelected(IOConnectionInfo.FromPath(data.DataString), requestCode);

View File

@@ -62,13 +62,6 @@
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
@@ -76,6 +69,19 @@
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotations" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-compat/24.2.0/jars" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-compat/24.2.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-core-ui/24.2.0/jars" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-core-ui/24.2.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-core-utils/24.2.0/jars" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-core-utils/24.2.0/jars" />
@@ -86,6 +92,11 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.microsoft.aad/adal/1.1.19/jars" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.microsoft.aad/adal/1.1.19/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.microsoft.services.msa/msa-auth/0.8.6/jars" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.microsoft.services.msa/msa-auth/0.8.6/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.onedrive.sdk/onedrive-sdk-android/1.2.2/jars" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.onedrive.sdk/onedrive-sdk-android/1.2.2/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard-rules" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />

View File

@@ -31,4 +31,7 @@
-keep interface keepass2android.javafilestorage.** {*; } -keep interface keepass2android.javafilestorage.** {*; }
-keep interface keepass2android.javafilestorage.JavaFileStorage$FileStorageSetupActivity {*; } -keep interface keepass2android.javafilestorage.JavaFileStorage$FileStorageSetupActivity {*; }
-dontwarn
-ignorewarnings

View File

@@ -15,7 +15,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:singleLine="true" android:singleLine="true"
android:inputType="textNoSuggestions" android:inputType="textNoSuggestions"
android:text="" android:text="https://daigers.diskstation.me:5006/Keepass2Android/Apps/Keepass2Android/"
android:hint="Server URL" /> android:hint="Server URL" />
</LinearLayout> </LinearLayout>
<EditText <EditText
@@ -32,7 +32,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="textPassword" android:inputType="textPassword"
android:singleLine="true" android:singleLine="true"
android:text="" android:text="$T3st17$"
android:hint="@string/hint_pass" /> android:hint="@string/hint_pass" />
</LinearLayout> </LinearLayout>

View File

@@ -38,7 +38,19 @@
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0"> <state vertical-scroll-proportion="0.0">
<caret line="406" column="0" selection-start-line="406" selection-start-column="0" selection-end-line="406" selection-end-column="0" /> <caret line="406" column="0" selection-start-line="406" selection-start-column="0" selection-end-line="406" selection-end-column="0" />
<folding /> <folding>
<element signature="imports" expanded="false" />
<element signature="e#1586#1587#0" expanded="false" />
<element signature="e#1622#1623#0" expanded="false" />
<element signature="e#1697#1698#0" expanded="false" />
<element signature="e#1749#1750#0" expanded="false" />
<element signature="e#2936#2937#0" expanded="false" />
<element signature="e#2969#2970#0" expanded="false" />
<element signature="e#13182#13183#0" expanded="false" />
<element signature="e#13236#13237#0" expanded="false" />
<element signature="e#13294#13295#0" expanded="false" />
<element signature="e#13348#13349#0" expanded="false" />
</folding>
</state> </state>
</provider> </provider>
</entry> </entry>
@@ -118,8 +130,8 @@
<file leaf-file-name="AndroidManifest.xml" pinned="false" current-in-tab="true"> <file leaf-file-name="AndroidManifest.xml" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/app/src/main/AndroidManifest.xml"> <entry file="file://$PROJECT_DIR$/app/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.60714287"> <state vertical-scroll-proportion="0.2236842">
<caret line="19" column="19" selection-start-line="19" selection-start-column="19" selection-end-line="19" selection-end-column="19" /> <caret line="7" column="25" selection-start-line="7" selection-start-column="25" selection-end-line="7" selection-end-column="25" />
<folding /> <folding />
</state> </state>
</provider> </provider>
@@ -1682,7 +1694,7 @@
</component> </component>
<component name="ToolWindowManager"> <component name="ToolWindowManager">
<frame x="-8" y="-8" width="1382" height="744" extended-state="6" /> <frame x="-8" y="-8" width="1382" height="744" extended-state="6" />
<editor active="false" /> <editor active="true" />
<layout> <layout>
<window_info id="Palette&#9;" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> <window_info id="Palette&#9;" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Designer" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="Designer" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
@@ -1698,10 +1710,11 @@
<window_info id="Gradle Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" /> <window_info id="Gradle Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Build Variants" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" /> <window_info id="Build Variants" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
<window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32764506" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Gradle" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="Gradle" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" /> <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.24962063" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.24962063" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.24886535" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" /> <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.24886535" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Application Servers" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> <window_info id="Application Servers" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
@@ -1709,7 +1722,6 @@
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" /> <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32764506" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32764506" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32764506" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Android" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32879046" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> <window_info id="Android" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32879046" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="SLIDING" type="SLIDING" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="SLIDING" type="SLIDING" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
@@ -1736,7 +1748,19 @@
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0"> <state vertical-scroll-proportion="0.0">
<caret line="406" column="0" selection-start-line="406" selection-start-column="0" selection-end-line="406" selection-end-column="0" /> <caret line="406" column="0" selection-start-line="406" selection-start-column="0" selection-end-line="406" selection-end-column="0" />
<folding /> <folding>
<element signature="imports" expanded="false" />
<element signature="e#1586#1587#0" expanded="false" />
<element signature="e#1622#1623#0" expanded="false" />
<element signature="e#1697#1698#0" expanded="false" />
<element signature="e#1749#1750#0" expanded="false" />
<element signature="e#2936#2937#0" expanded="false" />
<element signature="e#2969#2970#0" expanded="false" />
<element signature="e#13182#13183#0" expanded="false" />
<element signature="e#13236#13237#0" expanded="false" />
<element signature="e#13294#13295#0" expanded="false" />
<element signature="e#13348#13349#0" expanded="false" />
</folding>
</state> </state>
</provider> </provider>
</entry> </entry>
@@ -1960,7 +1984,19 @@
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0"> <state vertical-scroll-proportion="0.0">
<caret line="406" column="0" selection-start-line="406" selection-start-column="0" selection-end-line="406" selection-end-column="0" /> <caret line="406" column="0" selection-start-line="406" selection-start-column="0" selection-end-line="406" selection-end-column="0" />
<folding /> <folding>
<element signature="imports" expanded="false" />
<element signature="e#1586#1587#0" expanded="false" />
<element signature="e#1622#1623#0" expanded="false" />
<element signature="e#1697#1698#0" expanded="false" />
<element signature="e#1749#1750#0" expanded="false" />
<element signature="e#2936#2937#0" expanded="false" />
<element signature="e#2969#2970#0" expanded="false" />
<element signature="e#13182#13183#0" expanded="false" />
<element signature="e#13236#13237#0" expanded="false" />
<element signature="e#13294#13295#0" expanded="false" />
<element signature="e#13348#13349#0" expanded="false" />
</folding>
</state> </state>
</provider> </provider>
</entry> </entry>
@@ -1974,8 +2010,8 @@
</entry> </entry>
<entry file="file://$PROJECT_DIR$/app/src/main/AndroidManifest.xml"> <entry file="file://$PROJECT_DIR$/app/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.60714287"> <state vertical-scroll-proportion="0.2236842">
<caret line="19" column="19" selection-start-line="19" selection-start-column="19" selection-end-line="19" selection-end-column="19" /> <caret line="7" column="25" selection-start-line="7" selection-start-column="25" selection-end-line="7" selection-end-column="25" />
<folding /> <folding />
</state> </state>
</provider> </provider>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="Keepass2AndroidPluginSDK2" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="Keepass2AndroidPluginSDK2" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":app" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
<option name="LIBRARY_PROJECT" value="true" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/mockable-Google-Inc.-Google-APIs-23.jar" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/resources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" scope="TEST" name="mockable-Google-Inc.-Google-APIs-23" level="project" />
<orderEntry type="library" exported="" name="effects-android-23" level="project" />
<orderEntry type="library" exported="" name="usb-android-23" level="project" />
<orderEntry type="library" exported="" name="maps-android-23" level="project" />
</component>
</module>

View File

@@ -0,0 +1,20 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 'Google Inc.:Google APIs:23'
buildToolsVersion '23.0.1'
defaultConfig {
minSdkVersion 8
targetSdkVersion 19
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
dependencies {
}

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<lint>
</lint>

View File

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

View File

@@ -0,0 +1,201 @@
package keepass2android.pluginsdk;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import org.json.JSONArray;
import org.json.JSONException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.PopupMenu;
public class AccessManager
{
private static final String _tag = "Kp2aPluginSDK";
private static final String PREF_KEY_SCOPE = "scope";
private static final String PREF_KEY_TOKEN = "token";
public static String stringArrayToString(ArrayList<String> values) {
JSONArray a = new JSONArray();
for (int i = 0; i < values.size(); i++) {
a.put(values.get(i));
}
if (!values.isEmpty()) {
return a.toString();
} else {
return null;
}
}
public static ArrayList<String> stringToStringArray(String s) {
ArrayList<String> strings = new ArrayList<String>();
if (TextUtils.isEmpty(s) == false) {
try {
JSONArray a = new JSONArray(s);
for (int i = 0; i < a.length(); i++) {
String url = a.optString(i);
strings.add(url);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return strings;
}
public static void storeAccessToken(Context ctx, String hostPackage, String accessToken, ArrayList<String> scopes)
{
SharedPreferences prefs = getPrefsForHost(ctx, hostPackage);
Editor edit = prefs.edit();
edit.putString(PREF_KEY_TOKEN, accessToken);
String scopesString = stringArrayToString(scopes);
edit.putString(PREF_KEY_SCOPE, scopesString);
edit.commit();
Log.d(_tag, "stored access token " + accessToken.substring(0, 4)+"... for "+scopes.size()+" scopes ("+scopesString+").");
SharedPreferences hostPrefs = ctx.getSharedPreferences("KP2A.PluginAccess.hosts", Context.MODE_PRIVATE);
if (!hostPrefs.contains(hostPackage))
{
hostPrefs.edit().putString(hostPackage, "").commit();
}
}
public static void preparePopup(Object popupMenu)
{
try
{
Field[] fields = popupMenu.getClass().getDeclaredFields();
for (Field field : fields) {
if ("mPopup".equals(field.getName())) {
field.setAccessible(true);
Object menuPopupHelper = field.get(popupMenu);
Class<?> classPopupHelper = Class.forName(menuPopupHelper
.getClass().getName());
Method setForceIcons = classPopupHelper.getMethod(
"setForceShowIcon", boolean.class);
setForceIcons.invoke(menuPopupHelper, true);
break;
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
private static SharedPreferences getPrefsForHost(Context ctx,
String hostPackage) {
SharedPreferences prefs = ctx.getSharedPreferences("KP2A.PluginAccess."+hostPackage, Context.MODE_PRIVATE);
return prefs;
}
public static String tryGetAccessToken(Context ctx, String hostPackage, ArrayList<String> scopes) {
if (TextUtils.isEmpty(hostPackage))
{
Log.d(_tag, "hostPackage is empty!");
return null;
}
Log.d(_tag, "trying to find prefs for "+hostPackage);
SharedPreferences prefs = getPrefsForHost(ctx, hostPackage);
String scopesString = prefs.getString(PREF_KEY_SCOPE, "");
Log.d(_tag, "available scopes: "+ scopesString);
ArrayList<String> currentScope = stringToStringArray(scopesString);
if (isSubset(scopes, currentScope))
{
return prefs.getString(PREF_KEY_TOKEN, null);
}
else
{
Log.d(_tag, "looks like scope changed. Access token invalid.");
return null;
}
}
public static boolean isSubset(ArrayList<String> requiredScopes,
ArrayList<String> availableScopes) {
for (String r: requiredScopes){
if (availableScopes.indexOf(r)<0)
{
Log.d(_tag, "Scope "+r+" not available. "+availableScopes.size());
return false;
}
}
return true;
}
public static void removeAccessToken(Context ctx, String hostPackage,
String accessToken) {
SharedPreferences prefs = getPrefsForHost(ctx, hostPackage);
Log.d(_tag, "removing AccessToken.");
if (prefs.getString(PREF_KEY_TOKEN, "").equals(accessToken))
{
Editor edit = prefs.edit();
edit.clear();
edit.commit();
}
SharedPreferences hostPrefs = ctx.getSharedPreferences("KP2A.PluginAccess.hosts", Context.MODE_PRIVATE);
if (hostPrefs.contains(hostPackage))
{
hostPrefs.edit().remove(hostPackage).commit();
}
}
public static Set<String> getAllHostPackages(Context ctx)
{
SharedPreferences prefs = ctx.getSharedPreferences("KP2A.PluginAccess.hosts", Context.MODE_PRIVATE);
Set<String> result = new HashSet<String>();
for (String host: prefs.getAll().keySet())
{
try
{
PackageInfo info = ctx.getPackageManager().getPackageInfo(host, PackageManager.GET_META_DATA);
//if we get here, the package is still there
result.add(host);
}
catch (PackageManager.NameNotFoundException e)
{
//host gone. ignore.
}
}
return result;
}
/**
* Returns a valid access token or throws PluginAccessException
*/
public static String getAccessToken(Context context, String hostPackage,
ArrayList<String> scopes) throws PluginAccessException {
String accessToken = tryGetAccessToken(context, hostPackage, scopes);
if (accessToken == null)
throw new PluginAccessException(hostPackage, scopes);
return accessToken;
}
}

View File

@@ -0,0 +1,48 @@
package keepass2android.pluginsdk;
public class KeepassDefs {
/// <summary>
/// Default identifier string for the title field. Should not contain
/// spaces, tabs or other whitespace.
/// </summary>
public static String TitleField = "Title";
/// <summary>
/// Default identifier string for the user name field. Should not contain
/// spaces, tabs or other whitespace.
/// </summary>
public static String UserNameField = "UserName";
/// <summary>
/// Default identifier string for the password field. Should not contain
/// spaces, tabs or other whitespace.
/// </summary>
public static String PasswordField = "Password";
/// <summary>
/// Default identifier string for the URL field. Should not contain
/// spaces, tabs or other whitespace.
/// </summary>
public static String UrlField = "URL";
/// <summary>
/// Default identifier string for the notes field. Should not contain
/// spaces, tabs or other whitespace.
/// </summary>
public static String NotesField = "Notes";
public static boolean IsStandardField(String strFieldName)
{
if(strFieldName == null)
return false;
if(strFieldName.equals(TitleField)) return true;
if(strFieldName.equals(UserNameField)) return true;
if(strFieldName.equals(PasswordField)) return true;
if(strFieldName.equals(UrlField)) return true;
if(strFieldName.equals(NotesField)) return true;
return false;
}
}

View File

@@ -0,0 +1,111 @@
package keepass2android.pluginsdk;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Intent;
import android.text.TextUtils;
public class Kp2aControl {
/**
* Creates and returns an intent to launch Keepass2Android for adding an entry with the given fields.
* @param fields Key/Value pairs of the field values. See KeepassDefs for standard keys.
* @param protectedFields List of keys of the protected fields.
* @return Intent to start Keepass2Android.
* @throws JSONException
*/
public static Intent getAddEntryIntent(HashMap<String, String> fields, ArrayList<String> protectedFields)
{
return getAddEntryIntent(new JSONObject(fields).toString(), protectedFields);
}
public static Intent getAddEntryIntent(String outputData, ArrayList<String> protectedFields)
{
Intent startKp2aIntent = new Intent(Strings.ACTION_START_WITH_TASK);
startKp2aIntent.addCategory(Intent.CATEGORY_DEFAULT);
startKp2aIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startKp2aIntent.putExtra("KP2A_APPTASK", "CreateEntryThenCloseTask");
startKp2aIntent.putExtra("ShowUserNotifications", "false"); //KP2A expects a StringExtra
startKp2aIntent.putExtra(Strings.EXTRA_ENTRY_OUTPUT_DATA, outputData);
if (protectedFields != null)
startKp2aIntent.putStringArrayListExtra(Strings.EXTRA_PROTECTED_FIELDS_LIST, protectedFields);
return startKp2aIntent;
}
/**
* Creates an intent to open a Password Entry matching searchText
* @param searchText queryString
* @param showUserNotifications if true, the notifications (copy to clipboard, keyboard) are displayed
* @param closeAfterOpen if true, the entry is opened and KP2A is immediately closed
* @return Intent to start KP2A with
*/
public static Intent getOpenEntryIntent(String searchText, boolean showUserNotifications, boolean closeAfterOpen)
{
Intent startKp2aIntent = new Intent(Strings.ACTION_START_WITH_TASK);
startKp2aIntent.addCategory(Intent.CATEGORY_DEFAULT);
startKp2aIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startKp2aIntent.putExtra("KP2A_APPTASK", "SearchUrlTask");
startKp2aIntent.putExtra("ShowUserNotifications", String.valueOf(showUserNotifications));
startKp2aIntent.putExtra("CloseAfterCreate", String.valueOf(closeAfterOpen));
startKp2aIntent.putExtra("UrlToSearch", searchText);
return startKp2aIntent;
}
/**
* Creates an intent to query a password entry from KP2A. The credentials are returned as Activity result.
* @param searchText Text to search for. Should be a URL or "androidapp://com.my.package."
* @return an Intent to start KP2A with
*/
public static Intent getQueryEntryIntent(String searchText)
{
Intent i = new Intent(Strings.ACTION_QUERY_CREDENTIALS);
if (!TextUtils.isEmpty(searchText))
i.putExtra(Strings.EXTRA_QUERY_STRING, searchText);
return i;
}
/**
* Creates an intent to query a password entry from KP2A, matching to the current app's package .
* The credentials are returned as Activity result.
* This requires SCOPE_QUERY_CREDENTIALS_FOR_OWN_PACKAGE.
* @return an Intent to start KP2A with
*/
public static Intent getQueryEntryIntentForOwnPackage()
{
return new Intent(Strings.ACTION_QUERY_CREDENTIALS_FOR_OWN_PACKAGE);
}
/**
* Converts the entry fields returned in an intent from a query to a hashmap.
* @param intent data received in onActivityResult after getQueryEntryIntent(ForOwnPackage)
* @return HashMap with keys = field names (see KeepassDefs for standard keys) and values = values
*/
public static HashMap<String, String> getEntryFieldsFromIntent(Intent intent)
{
HashMap<String, String> res = new HashMap<String, String>();
try {
JSONObject json = new JSONObject(intent.getStringExtra(Strings.EXTRA_ENTRY_OUTPUT_DATA));
for(Iterator<String> iter = json.keys();iter.hasNext();) {
String key = iter.next();
String value = json.get(key).toString();
res.put(key, value);
}
} catch (JSONException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
return res;
}
}

View File

@@ -0,0 +1,101 @@
package keepass2android.pluginsdk;
import java.util.ArrayList;
import android.R.anim;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
/**
* Broadcast flow between Host and Plugin
* ======================================
*
* The host is responsible for deciding when to initiate the session. It
* should initiate the session as soon as plugins are required or when a plugin
* has been updated through the OS.
* It will then send a broadcast to request the currently required scope.
* The plugin then sends a broadcast to the app which scope is required. If an
* access token is already available, it's sent along with the requset.
*
* If a previous permission has been revoked (or the app settings cleared or the
* permissions have been extended or the token is invalid for any other reason)
* the host will answer with a Revoked-Permission broadcast (i.e. the plugin is
* unconnected.)
*
* Unconnected plugins must be permitted by the user (requiring user action).
* When the user grants access, the plugin will receive an access token for
* the host. This access token is valid for the requested scope. If the scope
* changes (e.g after an update of the plugin), the access token becomes invalid.
*
*/
public abstract class PluginAccessBroadcastReceiver extends BroadcastReceiver {
private static final String _tag = "Kp2aPluginSDK";
@Override
public void onReceive(Context ctx, Intent intent) {
String action = intent.getAction();
android.util.Log.d(_tag, "received broadcast with action="+action);
if (action == null)
return;
if (action.equals(Strings.ACTION_TRIGGER_REQUEST_ACCESS))
{
requestAccess(ctx, intent);
} else if (action.equals(Strings.ACTION_RECEIVE_ACCESS))
{
receiveAccess(ctx, intent);
} else if (action.equals(Strings.ACTION_REVOKE_ACCESS))
{
revokeAccess(ctx, intent);
} else
{
//TODO handle unexpected action
}
}
private void revokeAccess(Context ctx, Intent intent) {
String senderPackage = intent.getStringExtra(Strings.EXTRA_SENDER);
String accessToken = intent.getStringExtra(Strings.EXTRA_ACCESS_TOKEN);
//this intent must send the invalid(ated) token to prevent malicious apps
//from revoking access of all plugins.
AccessManager.removeAccessToken(ctx, senderPackage, accessToken);
}
private void receiveAccess(Context ctx, Intent intent) {
String senderPackage = intent.getStringExtra(Strings.EXTRA_SENDER);
String accessToken = intent.getStringExtra(Strings.EXTRA_ACCESS_TOKEN);
AccessManager.storeAccessToken(ctx, senderPackage, accessToken, getScopes());
}
public void requestAccess(Context ctx, Intent intent) {
String senderPackage = intent.getStringExtra(Strings.EXTRA_SENDER);
String requestToken = intent.getStringExtra(Strings.EXTRA_REQUEST_TOKEN);
Intent rpi = new Intent(Strings.ACTION_REQUEST_ACCESS);
rpi.setPackage(senderPackage);
rpi.putExtra(Strings.EXTRA_SENDER, ctx.getPackageName());
rpi.putExtra(Strings.EXTRA_REQUEST_TOKEN, requestToken);
String token = AccessManager.tryGetAccessToken(ctx, senderPackage, getScopes());
if (token != null)
{
rpi.putExtra(Strings.EXTRA_ACCESS_TOKEN, token);
}
rpi.putStringArrayListExtra(Strings.EXTRA_SCOPES, getScopes());
Log.d(_tag, "requesting access for "+getScopes().size()+" tokens.");
ctx.sendBroadcast(rpi);
}
/**
*
* @return the list of required scopes for this plugin.
*/
abstract public ArrayList<String> getScopes();
}

View File

@@ -0,0 +1,21 @@
package keepass2android.pluginsdk;
import java.util.ArrayList;
public class PluginAccessException extends Exception {
public PluginAccessException(String what)
{
super(what);
}
public PluginAccessException(String hostPackage, ArrayList<String> scopes) {
}
/**
*
*/
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,303 @@
package keepass2android.pluginsdk;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public abstract class PluginActionBroadcastReceiver extends BroadcastReceiver {
protected abstract class PluginActionBase
{
protected Context _context;
protected Intent _intent;
public PluginActionBase(Context context, Intent intent)
{
_context = context;
_intent = intent;
}
public String getHostPackage() {
return _intent.getStringExtra(Strings.EXTRA_SENDER);
}
public Context getContext()
{
return _context;
}
}
protected abstract class PluginEntryActionBase extends PluginActionBase
{
public PluginEntryActionBase(Context context, Intent intent)
{
super(context, intent);
}
protected HashMap<String, String> getEntryFieldsFromIntent()
{
HashMap<String, String> res = new HashMap<String, String>();
try {
JSONObject json = new JSONObject(_intent.getStringExtra(Strings.EXTRA_ENTRY_OUTPUT_DATA));
for(Iterator<String> iter = json.keys();iter.hasNext();) {
String key = iter.next();
String value = json.get(key).toString();
Log.d("KP2APluginSDK", "received " + key+"/"+value);
res.put(key, value);
}
} catch (JSONException e) {
e.printStackTrace();
}
return res;
}
protected String[] getProtectedFieldsListFromIntent()
{
return _intent.getStringArrayExtra(Strings.EXTRA_PROTECTED_FIELDS_LIST);
}
public String getEntryId()
{
return _intent.getStringExtra(Strings.EXTRA_ENTRY_ID);
}
public void setEntryField(String fieldId, String fieldValue, boolean isProtected) throws PluginAccessException
{
Intent i = new Intent(Strings.ACTION_SET_ENTRY_FIELD);
ArrayList<String> scope = new ArrayList<String>();
scope.add(Strings.SCOPE_CURRENT_ENTRY);
i.putExtra(Strings.EXTRA_ACCESS_TOKEN, AccessManager.getAccessToken(_context, getHostPackage(), scope));
i.setPackage(getHostPackage());
i.putExtra(Strings.EXTRA_SENDER, _context.getPackageName());
i.putExtra(Strings.EXTRA_FIELD_VALUE, fieldValue);
i.putExtra(Strings.EXTRA_ENTRY_ID, getEntryId());
i.putExtra(Strings.EXTRA_FIELD_ID, fieldId);
i.putExtra(Strings.EXTRA_FIELD_PROTECTED, isProtected);
_context.sendBroadcast(i);
}
}
protected class ActionSelectedAction extends PluginEntryActionBase
{
public ActionSelectedAction(Context ctx, Intent intent) {
super(ctx, intent);
}
/**
*
* @return the Bundle associated with the action. This bundle can be set in OpenEntry.add(Entry)FieldAction
*/
public Bundle getActionData()
{
return _intent.getBundleExtra(Strings.EXTRA_ACTION_DATA);
}
/**
*
* @return the field id which was selected. null if an entry action (in the options menu) was selected.
*/
public String getFieldId()
{
return _intent.getStringExtra(Strings.EXTRA_FIELD_ID);
}
/**
*
* @return true if an entry action, i.e. an option from the options menu, was selected. False if an option
* in a popup menu for a certain field was selected.
*/
public boolean isEntryAction()
{
return getFieldId() == null;
}
/**
*
* @return a hashmap containing the entry fields in key/value form
*/
public HashMap<String, String> getEntryFields()
{
return getEntryFieldsFromIntent();
}
/**
*
* @return an array with the keys of all protected fields in the entry
*/
public String[] getProtectedFieldsList()
{
return getProtectedFieldsListFromIntent();
}
}
protected class CloseEntryViewAction extends PluginEntryActionBase
{
public CloseEntryViewAction(Context context, Intent intent) {
super(context, intent);
}
public String getEntryId()
{
return _intent.getStringExtra(Strings.EXTRA_ENTRY_ID);
}
}
protected class OpenEntryAction extends PluginEntryActionBase
{
public OpenEntryAction(Context context, Intent intent)
{
super(context, intent);
}
public HashMap<String, String> getEntryFields()
{
return getEntryFieldsFromIntent();
}
/**
*
* @return an array with the keys of all protected fields in the entry
*/
public String[] getProtectedFieldsList()
{
return getProtectedFieldsListFromIntent();
}
public void addEntryAction(String actionDisplayText, int actionIconResourceId, Bundle actionData) throws PluginAccessException
{
addEntryFieldAction(null, null, actionDisplayText, actionIconResourceId, actionData);
}
public void addEntryFieldAction(String actionId, String fieldId, String actionDisplayText, int actionIconResourceId, Bundle actionData) throws PluginAccessException
{
Intent i = new Intent(Strings.ACTION_ADD_ENTRY_ACTION);
ArrayList<String> scope = new ArrayList<String>();
scope.add(Strings.SCOPE_CURRENT_ENTRY);
i.putExtra(Strings.EXTRA_ACCESS_TOKEN, AccessManager.getAccessToken(_context, getHostPackage(), scope));
i.setPackage(getHostPackage());
i.putExtra(Strings.EXTRA_SENDER, _context.getPackageName());
i.putExtra(Strings.EXTRA_ACTION_DATA, actionData);
i.putExtra(Strings.EXTRA_ACTION_DISPLAY_TEXT, actionDisplayText);
i.putExtra(Strings.EXTRA_ACTION_ICON_RES_ID, actionIconResourceId);
i.putExtra(Strings.EXTRA_ENTRY_ID, getEntryId());
i.putExtra(Strings.EXTRA_FIELD_ID, fieldId);
i.putExtra(Strings.EXTRA_ACTION_ID, actionId);
_context.sendBroadcast(i);
}
}
protected class DatabaseAction extends PluginActionBase
{
public DatabaseAction(Context context, Intent intent) {
super(context, intent);
}
public String getFileDisplayName()
{
return _intent.getStringExtra(Strings.EXTRA_DATABASE_FILE_DISPLAYNAME);
}
public String getFilePath()
{
return _intent.getStringExtra(Strings.EXTRA_DATABASE_FILEPATH);
}
public String getAction()
{
return _intent.getAction();
}
}
//EntryOutputModified is very similar to OpenEntry because it receives the same
//data (+ the field id which was modified)
protected class EntryOutputModifiedAction extends OpenEntryAction
{
public EntryOutputModifiedAction(Context context, Intent intent)
{
super(context, intent);
}
public String getModifiedFieldId()
{
return _intent.getStringExtra(Strings.EXTRA_FIELD_ID);
}
}
@Override
public void onReceive(Context ctx, Intent intent) {
String action = intent.getAction();
android.util.Log.d("KP2A.pluginsdk", "received broadcast in PluginActionBroadcastReceiver with action="+action);
if (action == null)
return;
if (action.equals(Strings.ACTION_OPEN_ENTRY))
{
openEntry(new OpenEntryAction(ctx, intent));
}
else if (action.equals(Strings.ACTION_CLOSE_ENTRY_VIEW))
{
closeEntryView(new CloseEntryViewAction(ctx, intent));
}
else if (action.equals(Strings.ACTION_ENTRY_ACTION_SELECTED))
{
actionSelected(new ActionSelectedAction(ctx, intent));
}
else if (action.equals(Strings.ACTION_ENTRY_OUTPUT_MODIFIED))
{
entryOutputModified(new EntryOutputModifiedAction(ctx, intent));
}
else if (action.equals(Strings.ACTION_LOCK_DATABASE)
|| action.equals(Strings.ACTION_UNLOCK_DATABASE)
|| action.equals(Strings.ACTION_OPEN_DATABASE)
|| action.equals(Strings.ACTION_CLOSE_DATABASE))
{
dbAction(new DatabaseAction(ctx, intent));
}
else
{
//TODO handle unexpected action
}
}
protected void closeEntryView(CloseEntryViewAction closeEntryView) {}
protected void actionSelected(ActionSelectedAction actionSelected) {}
protected void openEntry(OpenEntryAction oe) {}
protected void entryOutputModified(EntryOutputModifiedAction eom) {}
protected void dbAction(DatabaseAction db) {}
}

View File

@@ -0,0 +1,190 @@
package keepass2android.pluginsdk;
public class Strings {
/**
* Plugin is notified about actions like open/close/update a database.
*/
public static final String SCOPE_DATABASE_ACTIONS = "keepass2android.SCOPE_DATABASE_ACTIONS";
/**
* Plugin is notified when an entry is opened.
*/
public static final String SCOPE_CURRENT_ENTRY = "keepass2android.SCOPE_CURRENT_ENTRY";
/**
* Plugin may query credentials for its own package
*/
public static final String SCOPE_QUERY_CREDENTIALS_FOR_OWN_PACKAGE = "keepass2android.SCOPE_QUERY_CREDENTIALS_FOR_OWN_PACKAGE";
/**
* Plugin may query credentials for a deliberate package
*/
public static final String SCOPE_QUERY_CREDENTIALS = "keepass2android.SCOPE_QUERY_CREDENTIALS";
/**
* Extra key to transfer a (json serialized) list of scopes
*/
public static final String EXTRA_SCOPES = "keepass2android.EXTRA_SCOPES";
public static final String EXTRA_PLUGIN_PACKAGE = "keepass2android.EXTRA_PLUGIN_PACKAGE";
/**
* Extra key for sending the package name of the sender of a broadcast.
* Should be set in every broadcast.
*/
public static final String EXTRA_SENDER = "keepass2android.EXTRA_SENDER";
/**
* Extra key for sending a request token. The request token is passed from
* KP2A to the plugin. It's used in the authorization process.
*/
public static final String EXTRA_REQUEST_TOKEN = "keepass2android.EXTRA_REQUEST_TOKEN";
/**
* Action to start KP2A with an AppTask
*/
public static final String ACTION_START_WITH_TASK = "keepass2android.ACTION_START_WITH_TASK";
/**
* Action sent from KP2A to the plugin to indicate that the plugin should request
* access (sending it's scopes)
*/
public static final String ACTION_TRIGGER_REQUEST_ACCESS = "keepass2android.ACTION_TRIGGER_REQUEST_ACCESS";
/**
* Action sent from the plugin to KP2A including the scopes.
*/
public static final String ACTION_REQUEST_ACCESS = "keepass2android.ACTION_REQUEST_ACCESS";
/**
* Action sent from the KP2A to the plugin when the user grants access.
* Will contain an access token.
*/
public static final String ACTION_RECEIVE_ACCESS = "keepass2android.ACTION_RECEIVE_ACCESS";
/**
* Action sent from KP2A to the plugin to indicate that access is not or no longer valid.
*/
public static final String ACTION_REVOKE_ACCESS = "keepass2android.ACTION_REVOKE_ACCESS";
/**
* Action for startActivity(). Opens an activity in the Plugin Host to edit the plugin settings (i.e. enable it)
*/
public static final String ACTION_EDIT_PLUGIN_SETTINGS = "keepass2android.ACTION_EDIT_PLUGIN_SETTINGS";
/**
* Action sent from KP2A to the plugin to indicate that an entry was opened.
* The Intent contains the full entry data.
*/
public static final String ACTION_OPEN_ENTRY= "keepass2android.ACTION_OPEN_ENTRY";
/**
* Action sent from KP2A to the plugin to indicate that an entry output field was modified/added.
* The Intent contains the full new entry data.
*/
public static final String ACTION_ENTRY_OUTPUT_MODIFIED= "keepass2android.ACTION_ENTRY_OUTPUT_MODIFIED";
/**
* Action sent from KP2A to the plugin to indicate that an entry activity was closed.
*/
public static final String ACTION_CLOSE_ENTRY_VIEW= "keepass2android.ACTION_CLOSE_ENTRY_VIEW";
/**
* Extra key for a string containing the GUID of the entry.
*/
public static final String EXTRA_ENTRY_ID= "keepass2android.EXTRA_ENTRY_DATA";
/**
* Json serialized data of the PwEntry (C# class) representing the opened entry.
* currently not implemented.
*/
//public static final String EXTRA_ENTRY_DATA = "keepass2android.EXTRA_ENTRY_DATA";
/**
* Json serialized list of fields, transformed using the database context (i.e. placeholders are replaced already)
*/
public static final String EXTRA_ENTRY_OUTPUT_DATA = "keepass2android.EXTRA_ENTRY_OUTPUT_DATA";
/**
* Json serialized lisf of field keys, specifying which field of the EXTRA_ENTRY_OUTPUT_DATA is protected.
*/
public static final String EXTRA_PROTECTED_FIELDS_LIST = "keepass2android.EXTRA_PROTECTED_FIELDS_LIST";
/**
* Extra key for passing the access token (both ways)
*/
public static final String EXTRA_ACCESS_TOKEN = "keepass2android.EXTRA_ACCESS_TOKEN";
/**
* Action for an intent from the plugin to KP2A to add menu options regarding the currently open entry.
* Requires SCOPE_CURRENT_ENTRY.
*/
public static final String ACTION_ADD_ENTRY_ACTION = "keepass2android.ACTION_ADD_ENTRY_ACTION";
public static final String EXTRA_ACTION_DISPLAY_TEXT = "keepass2android.EXTRA_ACTION_DISPLAY_TEXT";
public static final String EXTRA_ACTION_ICON_RES_ID = "keepass2android.EXTRA_ACTION_ICON_RES_ID";
public static final String EXTRA_FIELD_ID = "keepass2android.EXTRA_FIELD_ID";
/**
* Used to pass an id for the action. Each actionId may occur only once per field, otherwise the previous
* action with same id is replaced by the new action.
*/
public static final String EXTRA_ACTION_ID = "keepass2android.EXTRA_ACTION_ID";
/** Extra for ACTION_ADD_ENTRY_ACTION and ACTION_ENTRY_ACTION_SELECTED to pass data specifying the action parameters.*/
public static final String EXTRA_ACTION_DATA = "keepass2android.EXTRA_ACTION_DATA";
/**
* Action for an intent from KP2A to the plugin when an action added with ACTION_ADD_ENTRY_ACTION was selected by the user.
*
*/
public static final String ACTION_ENTRY_ACTION_SELECTED = "keepass2android.ACTION_ENTRY_ACTION_SELECTED";
/**
* Extra key for the string which is used to query the credentials. This should be either a URL for
* a web login (google.com or a full URI) or something in the form "androidapp://com.my.package"
*/
public static final String EXTRA_QUERY_STRING = "keepass2android.EXTRA_QUERY_STRING";
/**
* Action when plugin wants to query credentials for its own package
*/
public static final String ACTION_QUERY_CREDENTIALS_FOR_OWN_PACKAGE = "keepass2android.ACTION_QUERY_CREDENTIALS_FOR_OWN_PACKAGE";
/**
* Action when plugin wants to query credentials for a deliberate package
* The query string is passed as intent data
*/
public static final String ACTION_QUERY_CREDENTIALS = "keepass2android.ACTION_QUERY_CREDENTIALS";
/**
* Action for an intent from the plugin to KP2A to set (i.e. add or update) a field in the entry.
* May be used to update existing or add new fields at any time while the entry is opened.
*/
public static final String ACTION_SET_ENTRY_FIELD = "keepass2android.ACTION_SET_ENTRY_FIELD";
/** Actions for an intent from KP2A to the plugin to inform that a database was opened, closed, quicklocked or quickunlocked.*/
public static final String ACTION_OPEN_DATABASE = "keepass2android.ACTION_OPEN_DATABASE";
public static final String ACTION_CLOSE_DATABASE = "keepass2android.ACTION_CLOSE_DATABASE";
public static final String ACTION_LOCK_DATABASE = "keepass2android.ACTION_LOCK_DATABASE";
public static final String ACTION_UNLOCK_DATABASE = "keepass2android.ACTION_UNLOCK_DATABASE";
/** Extra for ACTION_OPEN_DATABASE and ACTION_CLOSE_DATABASE containing a filepath which is used
* by KP2A internally to identify the file. Use only where necessary, might contain credentials
* for accessing the file (on remote storage).*/
public static final String EXTRA_DATABASE_FILEPATH = "keepass2android.EXTRA_DATABASE_FILEPATH";
/** Extra for ACTION_OPEN_DATABASE and ACTION_CLOSE_DATABASE containing a filepath which can be
* displayed to the user.*/
public static final String EXTRA_DATABASE_FILE_DISPLAYNAME = "keepass2android.EXTRA_DATABASE_FILE_DISPLAYNAME";
public static final String EXTRA_FIELD_VALUE = "keepass2android.EXTRA_FIELD_VALUE";
public static final String EXTRA_FIELD_PROTECTED = "keepass2android.EXTRA_FIELD_PROTECTED";
public static final String PREFIX_STRING = "STRING_";
public static final String PREFIX_BINARY = "BINARY_";
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,11 @@
<resources>
<!--
Base application theme for API 11+. This theme completely replaces
AppBaseTheme from res/values/styles.xml on API 11+ devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
<!-- API 11 theme customizations can go here. -->
</style>
</resources>

View File

@@ -0,0 +1,12 @@
<resources>
<!--
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.
-->
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<!-- API 14 theme customizations can go here. -->
</style>
</resources>

View File

@@ -0,0 +1,10 @@
<resources>
<!--
Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively).
-->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>

View File

@@ -0,0 +1,7 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Keepass2Android Plugin SDK</string>
</resources>

View File

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

@@ -0,0 +1,15 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
}
}
allprojects {
repositories {
jcenter()
}
}

View File

@@ -0,0 +1,6 @@
#Wed Apr 10 15:27:10 PDT 2013
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip

View File

@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

View File

@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1,35 @@
ECLIPSE ANDROID PROJECT IMPORT SUMMARY
======================================
Ignored Files:
--------------
The following files were *not* copied into the new Gradle project; you
should evaluate whether these are still needed in your project and if
so manually move them:
* proguard-project.txt
Moved Files:
------------
Android Gradle projects use a different directory structure than ADT
Eclipse projects. Here's how the projects were restructured:
* AndroidManifest.xml => app\src\main\AndroidManifest.xml
* lint.xml => app\lint.xml
* res\ => app\src\main\res\
* src\ => app\src\main\java\
Next Steps:
-----------
You can now build the project. The Gradle project needs network
connectivity to download dependencies.
Bugs:
-----
If for some reason your project does not build, and you determine that
it is due to a bug or limitation of the Eclipse to Gradle importer,
please file a bug at http://b.android.com with category
Component-Tools.
(This import summary is for your information only, and can be deleted
after import once you are satisfied with the results.)

View File

@@ -0,0 +1,11 @@
## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Mon Apr 10 10:51:25 CEST 2017
sdk.dir=C\:\\Users\\Philipp\\AppData\\Local\\Xamarin\\Universal\\AndroidSDK

View File

@@ -0,0 +1 @@
include ':app'

View File

@@ -1157,6 +1157,9 @@ namespace keepass2android
Finish(); Finish();
return false; return false;
} }
IoUtil.TryTakePersistablePermissions(this.ContentResolver, i.Data);
} }

View File

@@ -36,7 +36,7 @@
<string name="app_name_debug">Keepass2Android Debug</string> <string name="app_name_debug">Keepass2Android Debug</string>
<string name="library_name"></string> <string name="library_name"></string>
<string name="default_file_path">/keepass/keepass.kdbx</string> <string name="default_file_path">/keepass/keepass.kdbx</string>
<string name="donate_url"><![CDATA[http://philipp.crocoll.net/donate.php?lang=%1$s&app=%2$s]]></string> <string name="donate_url"><![CDATA[https://philipp.crocoll.net/donate.php?lang=%1$s&app=%2$s]]></string>
<string name="homepage">http://keepass2android.codeplex.com</string> <string name="homepage">http://keepass2android.codeplex.com</string>
<string name="homepage_short">keepass2android.codeplex.com</string> <string name="homepage_short">keepass2android.codeplex.com</string>
<string name="further_author_names">Alex Vallat, Ben Rush, Matthieu, Wiktor Ławski</string> <string name="further_author_names">Alex Vallat, Ben Rush, Matthieu, Wiktor Ławski</string>