mirror of
https://github.com/moparisthebest/keepass2android
synced 2025-01-09 04:28:05 -05:00
First version of AutoFill Plugin
This commit is contained in:
parent
7e593960bd
commit
f6d0778a46
src
AutoFillPlugin
AccessReceiver.cs
KeePass.slnAssets
AutoFillPlugin.csprojCredentials.csGettingStarted.XamarinKp2aAccessibilityService.csLookupCredentialsActivity.csMainActivity.csProperties
Resources
37
src/AutoFillPlugin/AccessReceiver.cs
Normal file
37
src/AutoFillPlugin/AccessReceiver.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Android.App;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.OS;
|
||||||
|
using Android.Runtime;
|
||||||
|
using Android.Views;
|
||||||
|
using Android.Widget;
|
||||||
|
using Keepass2android.Pluginsdk;
|
||||||
|
|
||||||
|
namespace keepass2android.AutoFillPlugin
|
||||||
|
{
|
||||||
|
[BroadcastReceiver(Exported = true)]
|
||||||
|
[IntentFilter(new[] { Strings.ActionTriggerRequestAccess, Strings.ActionReceiveAccess, Strings.ActionRevokeAccess })]
|
||||||
|
public class AccessReceiver : PluginAccessBroadcastReceiver
|
||||||
|
{
|
||||||
|
public override void OnReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
Android.Util.Log.Debug("KP2AAS", intent.Action);
|
||||||
|
base.OnReceive(context, intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IList<string> Scopes
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new List<string>
|
||||||
|
{
|
||||||
|
Strings.ScopeQueryCredentials
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
src/AutoFillPlugin/Assets/AboutAssets.txt
Normal file
19
src/AutoFillPlugin/Assets/AboutAssets.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Any raw assets you want to be deployed with your application can be placed in
|
||||||
|
this directory (and child directories) and given a Build Action of "AndroidAsset".
|
||||||
|
|
||||||
|
These files will be deployed with you package and will be accessible using Android's
|
||||||
|
AssetManager, like this:
|
||||||
|
|
||||||
|
public class ReadAsset : Activity
|
||||||
|
{
|
||||||
|
protected override void OnCreate (Bundle bundle)
|
||||||
|
{
|
||||||
|
base.OnCreate (bundle);
|
||||||
|
|
||||||
|
InputStream input = Assets.Open ("my_asset.txt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Additionally, some Android functions will automatically load asset files:
|
||||||
|
|
||||||
|
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
|
105
src/AutoFillPlugin/AutoFillPlugin.csproj
Normal file
105
src/AutoFillPlugin/AutoFillPlugin.csproj
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProductVersion>8.0.30703</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>{6FF440E6-E8FF-4E43-8221-9E3972F14812}</ProjectGuid>
|
||||||
|
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>keepass2android.AutoFillPlugin</RootNamespace>
|
||||||
|
<AssemblyName>AutoFillPlugin</AssemblyName>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<AndroidApplication>true</AndroidApplication>
|
||||||
|
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
|
||||||
|
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||||
|
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
|
||||||
|
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
|
||||||
|
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
|
||||||
|
<AndroidLinkMode>None</AndroidLinkMode>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
|
||||||
|
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Mono.Android" />
|
||||||
|
<Reference Include="mscorlib" />
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Json" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="AccessReceiver.cs" />
|
||||||
|
<Compile Include="Credentials.cs" />
|
||||||
|
<Compile Include="Kp2aAccessibilityService.cs" />
|
||||||
|
<Compile Include="LookupCredentialsActivity.cs" />
|
||||||
|
<Compile Include="MainActivity.cs" />
|
||||||
|
<Compile Include="Resources\Resource.Designer.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="GettingStarted.Xamarin" />
|
||||||
|
<None Include="Resources\AboutResources.txt" />
|
||||||
|
<None Include="Assets\AboutAssets.txt" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\values\Strings.xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\drawable\Icon.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="Properties\AndroidManifest.xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\xml\accserviceconfig.xml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</AndroidResource>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\drawable-xhdpi\ic_notify_keyboard.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\KeePassLib2Android\KeePassLib2Android.csproj">
|
||||||
|
<Project>{545b4a6b-8bba-4fbe-92fc-4ac060122a54}</Project>
|
||||||
|
<Name>KeePassLib2Android</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\PluginSdkBinding\PluginSdkBinding.csproj">
|
||||||
|
<Project>{3da3911e-36de-465e-8f15-f1991b6437e5}</Project>
|
||||||
|
<Name>PluginSdkBinding</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Resources\layout\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<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.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
21
src/AutoFillPlugin/Credentials.cs
Normal file
21
src/AutoFillPlugin/Credentials.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Android.App;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.OS;
|
||||||
|
using Android.Runtime;
|
||||||
|
using Android.Views;
|
||||||
|
using Android.Widget;
|
||||||
|
|
||||||
|
namespace keepass2android.AutoFillPlugin
|
||||||
|
{
|
||||||
|
public class Credentials
|
||||||
|
{
|
||||||
|
public string User;
|
||||||
|
public string Password;
|
||||||
|
public string Url;
|
||||||
|
}
|
||||||
|
}
|
4
src/AutoFillPlugin/GettingStarted.Xamarin
Normal file
4
src/AutoFillPlugin/GettingStarted.Xamarin
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<GettingStarted>
|
||||||
|
<LocalContent>GS\Android\CS\AndroidApp\GettingStarted.html</LocalContent>
|
||||||
|
<EmbeddedNavigation>false</EmbeddedNavigation>
|
||||||
|
</GettingStarted>
|
207
src/AutoFillPlugin/Kp2aAccessibilityService.cs
Normal file
207
src/AutoFillPlugin/Kp2aAccessibilityService.cs
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Android.App;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.OS;
|
||||||
|
using Android.Runtime;
|
||||||
|
using Android.Views;
|
||||||
|
using Android.Views.Accessibility;
|
||||||
|
using Android.Widget;
|
||||||
|
|
||||||
|
|
||||||
|
namespace keepass2android.AutoFillPlugin
|
||||||
|
{
|
||||||
|
//<meta-data android:name="android.accessibilityservice" android:resource="@xml/serviceconfig" />
|
||||||
|
[Service(Enabled =true, Permission= "android.permission.BIND_ACCESSIBILITY_SERVICE")]
|
||||||
|
[IntentFilter(new[] { "android.accessibilityservice.AccessibilityService" })]
|
||||||
|
[MetaData("android.accessibilityservice", Resource = "@xml/accserviceconfig")]
|
||||||
|
public class Kp2aAccessibilityService : Android.AccessibilityServices.AccessibilityService, IDialogInterfaceOnCancelListener
|
||||||
|
{
|
||||||
|
const string _logTag = "KP2AAS";
|
||||||
|
private const int autoFillNotificationId = 0;
|
||||||
|
private const string androidAppPrefix = "androidapp://";
|
||||||
|
|
||||||
|
public override void OnCreate()
|
||||||
|
{
|
||||||
|
base.OnCreate();
|
||||||
|
Android.Util.Log.Debug(_logTag, "OnCreate Service");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnServiceConnected()
|
||||||
|
{
|
||||||
|
Android.Util.Log.Debug(_logTag, "service connected");
|
||||||
|
base.OnServiceConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnAccessibilityEvent(AccessibilityEvent e)
|
||||||
|
{
|
||||||
|
|
||||||
|
Android.Util.Log.Debug(_logTag, "OnAccEvent");
|
||||||
|
bool cancelNotification = true;
|
||||||
|
if (e.EventType == EventTypes.WindowContentChanged || e.EventType == EventTypes.WindowStateChanged)
|
||||||
|
{
|
||||||
|
Android.Util.Log.Debug(_logTag, "event: " + e.EventType + ", package = " + e.PackageName);
|
||||||
|
var root = RootInActiveWindow;
|
||||||
|
if ((ExistsNodeOrChildren(root, n => n.WindowId == e.WindowId) && !ExistsNodeOrChildren(root, n => (n.ViewIdResourceName != null) && (n.ViewIdResourceName.StartsWith("com.android.systemui")))))
|
||||||
|
{
|
||||||
|
var allEditTexts = GetNodeOrChildren(root, n=> { return IsEditText(n); });
|
||||||
|
|
||||||
|
var usernameEdit = allEditTexts.TakeWhile(edit => (edit.Password == false)).LastOrDefault();
|
||||||
|
|
||||||
|
string searchString = androidAppPrefix + root.PackageName;
|
||||||
|
|
||||||
|
string url = androidAppPrefix + root.PackageName;
|
||||||
|
|
||||||
|
if (root.PackageName == "com.android.chrome")
|
||||||
|
{
|
||||||
|
var addressField = root.FindAccessibilityNodeInfosByViewId("com.android.chrome:id/url_bar").FirstOrDefault();
|
||||||
|
UrlFromAddressField(ref url, addressField);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (root.PackageName == "com.android.browser")
|
||||||
|
{
|
||||||
|
var addressField = root.FindAccessibilityNodeInfosByViewId("com.android.browser:id/url").FirstOrDefault();
|
||||||
|
UrlFromAddressField(ref url, addressField);
|
||||||
|
}
|
||||||
|
|
||||||
|
var emptyPasswordFields = GetNodeOrChildren(root, n => { return IsPasswordField(n); }).ToList();
|
||||||
|
if (emptyPasswordFields.Any())
|
||||||
|
{
|
||||||
|
if ((LookupCredentialsActivity.LastReceivedCredentials != null) && (LookupCredentialsActivity.LastReceivedCredentials.Url == url))
|
||||||
|
{
|
||||||
|
FillPassword(url, usernameEdit, emptyPasswordFields);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AskFillPassword(url, usernameEdit, emptyPasswordFields);
|
||||||
|
cancelNotification = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (cancelNotification)
|
||||||
|
((NotificationManager)GetSystemService(NotificationService)).Cancel(autoFillNotificationId);
|
||||||
|
|
||||||
|
}
|
||||||
|
private static void UrlFromAddressField(ref string url, AccessibilityNodeInfo addressField)
|
||||||
|
{
|
||||||
|
if (addressField != null)
|
||||||
|
{
|
||||||
|
url = addressField.Text;
|
||||||
|
if (!url.Contains("://"))
|
||||||
|
url = "http://" + url;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsPasswordField(AccessibilityNodeInfo n)
|
||||||
|
{
|
||||||
|
//if (n.Password) Android.Util.Log.Debug(_logTag, "pwdx with " + (n.Text == null ? "null" : n.Text));
|
||||||
|
var res = n.Password && string.IsNullOrEmpty(n.Text);
|
||||||
|
// if (n.Password) Android.Util.Log.Debug(_logTag, "pwd with " + n.Text + res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsEditText(AccessibilityNodeInfo n)
|
||||||
|
{
|
||||||
|
//it seems like n.Editable is not a good check as this is false for some fields which are actually editable, at least in tests with Chrome.
|
||||||
|
return (n.ClassName != null) && (n.ClassName.Contains("EditText"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AskFillPassword(string url, AccessibilityNodeInfo usernameEdit, IEnumerable<AccessibilityNodeInfo> passwordFields)
|
||||||
|
{
|
||||||
|
var runSearchIntent = new Intent(this, typeof(LookupCredentialsActivity));
|
||||||
|
runSearchIntent.PutExtra("url", url);
|
||||||
|
runSearchIntent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
|
||||||
|
var pending = PendingIntent.GetActivity(this, 0, runSearchIntent, PendingIntentFlags.UpdateCurrent);
|
||||||
|
|
||||||
|
var targetName = url;
|
||||||
|
|
||||||
|
if (url.StartsWith(androidAppPrefix))
|
||||||
|
{
|
||||||
|
var packageName = url.Substring(androidAppPrefix.Length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
targetName = PackageManager.GetPackageInfo(packageName, 0).ApplicationInfo.Name;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Android.Util.Log.Debug(_logTag, e.ToString());
|
||||||
|
targetName = packageName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
targetName = KeePassLib.Utility.UrlUtil.GetHost(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var builder = new Notification.Builder(this);
|
||||||
|
//TODO icon
|
||||||
|
//TODO plugin icon
|
||||||
|
builder.SetSmallIcon(Resource.Drawable.ic_notify_keyboard)
|
||||||
|
.SetContentText(GetString(Resource.String.NotificationContentText, new Java.Lang.Object[] { targetName }))
|
||||||
|
.SetContentTitle(GetString(Resource.String.NotificationTitle))
|
||||||
|
.SetWhen(Java.Lang.JavaSystem.CurrentTimeMillis())
|
||||||
|
.SetTicker( GetString(Resource.String.NotificationTickerText, new Java.Lang.Object[] { targetName }))
|
||||||
|
.SetVisibility(Android.App.NotificationVisibility.Secret)
|
||||||
|
.SetContentIntent(pending);
|
||||||
|
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
|
||||||
|
notificationManager.Notify(autoFillNotificationId, builder.Build());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FillPassword(string url, AccessibilityNodeInfo usernameEdit, IEnumerable<AccessibilityNodeInfo> passwordFields)
|
||||||
|
{
|
||||||
|
|
||||||
|
FillDataInTextField(usernameEdit, LookupCredentialsActivity.LastReceivedCredentials.User);
|
||||||
|
foreach (var pwd in passwordFields)
|
||||||
|
FillDataInTextField(pwd, LookupCredentialsActivity.LastReceivedCredentials.Password);
|
||||||
|
|
||||||
|
LookupCredentialsActivity.LastReceivedCredentials = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FillDataInTextField(AccessibilityNodeInfo edit, string newValue)
|
||||||
|
{
|
||||||
|
Bundle b = new Bundle();
|
||||||
|
b.PutString(AccessibilityNodeInfo.ActionArgumentSetTextCharsequence, newValue);
|
||||||
|
edit.PerformAction(Android.Views.Accessibility.Action.SetText, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ExistsNodeOrChildren(AccessibilityNodeInfo n, Func<AccessibilityNodeInfo, bool> p)
|
||||||
|
{
|
||||||
|
return GetNodeOrChildren(n, p).Any();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<AccessibilityNodeInfo> GetNodeOrChildren(AccessibilityNodeInfo n, Func<AccessibilityNodeInfo, bool> p)
|
||||||
|
{
|
||||||
|
if (n != null)
|
||||||
|
{
|
||||||
|
if (p(n))
|
||||||
|
yield return n;
|
||||||
|
for (int i = 0; i < n.ChildCount; i++)
|
||||||
|
{
|
||||||
|
foreach (var x in GetNodeOrChildren(n.GetChild(i), p))
|
||||||
|
yield return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnInterrupt()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCancel(IDialogInterface dialog)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
56
src/AutoFillPlugin/LookupCredentialsActivity.cs
Normal file
56
src/AutoFillPlugin/LookupCredentialsActivity.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Android.App;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.OS;
|
||||||
|
using Android.Runtime;
|
||||||
|
using Android.Views;
|
||||||
|
using Android.Widget;
|
||||||
|
|
||||||
|
using Keepass2android.Pluginsdk;
|
||||||
|
|
||||||
|
namespace keepass2android.AutoFillPlugin
|
||||||
|
{
|
||||||
|
[Activity(Label = "@string/LookupTitle", LaunchMode = Android.Content.PM.LaunchMode.SingleInstance)]
|
||||||
|
public class LookupCredentialsActivity : Activity
|
||||||
|
{
|
||||||
|
protected override void OnCreate(Bundle bundle)
|
||||||
|
{
|
||||||
|
base.OnCreate(bundle);
|
||||||
|
|
||||||
|
var url = Intent.GetStringExtra("url");
|
||||||
|
_lastQueriedUrl = url;
|
||||||
|
StartActivityForResult(Kp2aControl.GetQueryEntryIntent(url), 123);
|
||||||
|
}
|
||||||
|
|
||||||
|
string _lastQueriedUrl;
|
||||||
|
|
||||||
|
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
|
||||||
|
{
|
||||||
|
base.OnActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
var jsonOutput = new Org.Json.JSONObject(data.GetStringExtra(Strings.ExtraEntryOutputData));
|
||||||
|
Dictionary<string, string> output = new Dictionary<string, string>();
|
||||||
|
for (var iter = jsonOutput.Keys(); iter.HasNext;)
|
||||||
|
{
|
||||||
|
string key = iter.Next().ToString();
|
||||||
|
string value = jsonOutput.Get(key).ToString();
|
||||||
|
output[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string user = "", password = "";
|
||||||
|
output.TryGetValue(KeePassLib.PwDefs.UserNameField, out user);
|
||||||
|
output.TryGetValue(KeePassLib.PwDefs.PasswordField, out password);
|
||||||
|
|
||||||
|
LastReceivedCredentials = new Credentials() { User = user, Password = password, Url = _lastQueriedUrl };
|
||||||
|
|
||||||
|
Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Credentials LastReceivedCredentials;
|
||||||
|
}
|
||||||
|
}
|
25
src/AutoFillPlugin/MainActivity.cs
Normal file
25
src/AutoFillPlugin/MainActivity.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Android.App;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.OS;
|
||||||
|
using Android.Runtime;
|
||||||
|
using Android.Views;
|
||||||
|
using Android.Widget;
|
||||||
|
|
||||||
|
namespace keepass2android.AutoFillPlugin
|
||||||
|
{
|
||||||
|
[Activity(Label = "MainActivity", MainLauncher =true)]
|
||||||
|
public class MainActivity : Activity
|
||||||
|
{
|
||||||
|
protected override void OnCreate(Bundle bundle)
|
||||||
|
{
|
||||||
|
base.OnCreate(bundle);
|
||||||
|
|
||||||
|
// Create your application here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
src/AutoFillPlugin/Properties/AndroidManifest.xml
Normal file
5
src/AutoFillPlugin/Properties/AndroidManifest.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="AutoFillPlugin.AutoFillPlugin" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
|
||||||
|
<uses-sdk android:minSdkVersion="19" />
|
||||||
|
<application android:label="AutoFillPlugin" android:icon="@drawable/Icon"></application>
|
||||||
|
</manifest>
|
30
src/AutoFillPlugin/Properties/AssemblyInfo.cs
Normal file
30
src/AutoFillPlugin/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Android.App;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("AutoFillPlugin")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("AutoFillPlugin")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2015")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
50
src/AutoFillPlugin/Resources/AboutResources.txt
Normal file
50
src/AutoFillPlugin/Resources/AboutResources.txt
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
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.xml),
|
||||||
|
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-hdpi/
|
||||||
|
icon.png
|
||||||
|
|
||||||
|
drawable-ldpi/
|
||||||
|
icon.png
|
||||||
|
|
||||||
|
drawable-mdpi/
|
||||||
|
icon.png
|
||||||
|
|
||||||
|
layout/
|
||||||
|
main.xml
|
||||||
|
|
||||||
|
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
|
||||||
|
"Resource" that contains the tokens for each one of the resources included. For example,
|
||||||
|
for the above Resources layout, this is what the Resource class would expose:
|
||||||
|
|
||||||
|
public class Resource {
|
||||||
|
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 Resource.layout.main
|
||||||
|
to reference the layout/main.xml file, or Resource.strings.first_string to reference the first
|
||||||
|
string in the dictionary file values/strings.xml.
|
Binary file not shown.
After (image error) Size: 15 KiB |
BIN
src/AutoFillPlugin/Resources/drawable/Icon.png
Normal file
BIN
src/AutoFillPlugin/Resources/drawable/Icon.png
Normal file
Binary file not shown.
After (image error) Size: 4.0 KiB |
8
src/AutoFillPlugin/Resources/values/Strings.xml
Normal file
8
src/AutoFillPlugin/Resources/values/Strings.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="LookupTitle">Look up credentials</string>
|
||||||
|
<string name="ApplicationName">KP2A AutoFillPlugin</string>
|
||||||
|
<string name="NotificationTitle">Keepass2Android AutoFill</string>
|
||||||
|
<string name="NotificationContentText">AutoFill form for %1$s</string>
|
||||||
|
<string name="NotificationTickerText">AutoFill available for %1$s</string>
|
||||||
|
</resources>
|
11
src/AutoFillPlugin/Resources/xml/accserviceconfig.xml
Normal file
11
src/AutoFillPlugin/Resources/xml/accserviceconfig.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:description="@string/ApplicationName"
|
||||||
|
android:accessibilityEventTypes="typeAllMask"
|
||||||
|
android:accessibilityFlags="flagDefault"
|
||||||
|
android:accessibilityFeedbackType="feedbackSpoken"
|
||||||
|
android:notificationTimeout="100"
|
||||||
|
android:canRetrieveWindowContent="true"
|
||||||
|
|
||||||
|
/>
|
||||||
|
<!--android:settingsActivity="md58dca69cf5ce118dfdacac1ed5b2bbacf.MainActivity"-->
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 2013
|
# Visual Studio 14
|
||||||
VisualStudioVersion = 12.0.31101.0
|
VisualStudioVersion = 14.0.23107.0
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassLib2Android", "KeePassLib2Android\KeePassLib2Android.csproj", "{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassLib2Android", "KeePassLib2Android\KeePassLib2Android.csproj", "{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}"
|
||||||
EndProject
|
EndProject
|
||||||
@ -39,6 +39,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZlibAndroid", "ZlibAndroid\
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaterialTest2", "MaterialTest2\MaterialTest2.csproj", "{B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaterialTest2", "MaterialTest2\MaterialTest2.csproj", "{B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoFillPlugin", "AutoFillPlugin\AutoFillPlugin.csproj", "{6FF440E6-E8FF-4E43-8221-9E3972F14812}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -408,6 +410,42 @@ Global
|
|||||||
{B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.ReleaseNoNet|Mixed Platforms.Deploy.0 = Release|Any CPU
|
{B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.ReleaseNoNet|Mixed Platforms.Deploy.0 = Release|Any CPU
|
||||||
{B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
{B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||||
{B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
|
{B7BBC4A2-0301-4DFF-B03C-C88CD4F1F890}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Debug|Mixed Platforms.Deploy.0 = Debug|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Debug|Win32.Deploy.0 = Debug|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Debug|x64.Deploy.0 = Debug|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Release|Mixed Platforms.Deploy.0 = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Release|Win32.Build.0 = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Release|Win32.Deploy.0 = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.Release|x64.Deploy.0 = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.ReleaseNoNet|Any CPU.Deploy.0 = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.ReleaseNoNet|Mixed Platforms.Deploy.0 = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.ReleaseNoNet|Win32.Build.0 = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.ReleaseNoNet|Win32.Deploy.0 = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.ReleaseNoNet|x64.Build.0 = Release|Any CPU
|
||||||
|
{6FF440E6-E8FF-4E43-8221-9E3972F14812}.ReleaseNoNet|x64.Deploy.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
Loading…
Reference in New Issue
Block a user