mirror of
https://github.com/moparisthebest/keepass2android
synced 2024-11-22 17:22:17 -05:00
PluginHost-Test project: modified EntryActivity for receiving actions and fields
This commit is contained in:
parent
4697dbf41c
commit
07038d7549
@ -25,6 +25,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KP2AKdbLibraryBinding", "KP
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArtTestApp", "ArtTestApp\ArtTestApp.csproj", "{1FF6C335-A627-43C9-AAA7-CBAC2E74CD18}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArtTestApp", "ArtTestApp\ArtTestApp.csproj", "{1FF6C335-A627-43C9-AAA7-CBAC2E74CD18}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginHostTest", "PluginHostTest\PluginHostTest.csproj", "{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginSdkBinding", "PluginSdkBinding\PluginSdkBinding.csproj", "{3DA3911E-36DE-465E-8F15-F1991B6437E5}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -284,6 +288,48 @@ Global
|
|||||||
{1FF6C335-A627-43C9-AAA7-CBAC2E74CD18}.ReleaseNoNet|Mixed Platforms.Deploy.0 = Release|Any CPU
|
{1FF6C335-A627-43C9-AAA7-CBAC2E74CD18}.ReleaseNoNet|Mixed Platforms.Deploy.0 = Release|Any CPU
|
||||||
{1FF6C335-A627-43C9-AAA7-CBAC2E74CD18}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
{1FF6C335-A627-43C9-AAA7-CBAC2E74CD18}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||||
{1FF6C335-A627-43C9-AAA7-CBAC2E74CD18}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
|
{1FF6C335-A627-43C9-AAA7-CBAC2E74CD18}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Debug|Mixed Platforms.Deploy.0 = Debug|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Release|Mixed Platforms.Deploy.0 = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.ReleaseNoNet|Any CPU.Deploy.0 = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.ReleaseNoNet|Mixed Platforms.Deploy.0 = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||||
|
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||||
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
37
src/PluginHostTest/App.cs
Normal file
37
src/PluginHostTest/App.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using KeePassLib;
|
||||||
|
using KeePassLib.Keys;
|
||||||
|
using KeePassLib.Serialization;
|
||||||
|
|
||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
public class App
|
||||||
|
{
|
||||||
|
public class Kp2A
|
||||||
|
{
|
||||||
|
private static Db _mDb;
|
||||||
|
|
||||||
|
public class Db
|
||||||
|
{
|
||||||
|
public void SetEntry(PwEntry e)
|
||||||
|
{
|
||||||
|
KpDatabase = new PwDatabase();
|
||||||
|
KpDatabase.New(new IOConnectionInfo(), new CompositeKey());
|
||||||
|
|
||||||
|
KpDatabase.RootGroup.AddEntry(e, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PwDatabase KpDatabase
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Db GetDb()
|
||||||
|
{
|
||||||
|
if (_mDb == null)
|
||||||
|
_mDb = new Db();
|
||||||
|
return _mDb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/PluginHostTest/CopyToClipboardService.cs
Normal file
14
src/PluginHostTest/CopyToClipboardService.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using Android.Content;
|
||||||
|
using Android.Widget;
|
||||||
|
using KeePassLib.Security;
|
||||||
|
|
||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
internal class CopyToClipboardService
|
||||||
|
{
|
||||||
|
public static void CopyValueToClipboardWithTimeout(Context ctx, string text)
|
||||||
|
{
|
||||||
|
Toast.MakeText(ctx, text, ToastLength.Short).Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,10 +19,12 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
|
using Android.Runtime;
|
||||||
|
using Android.Text;
|
||||||
using Android.Views;
|
using Android.Views;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
using Android.Preferences;
|
using Android.Preferences;
|
||||||
@ -32,79 +34,412 @@ using Android.Content.PM;
|
|||||||
using Android.Webkit;
|
using Android.Webkit;
|
||||||
using Android.Graphics;
|
using Android.Graphics;
|
||||||
using Java.IO;
|
using Java.IO;
|
||||||
|
using KeePassLib;
|
||||||
|
using KeePassLib.Security;
|
||||||
|
using Keepass2android.Pluginsdk;
|
||||||
using PluginHostTest;
|
using PluginHostTest;
|
||||||
|
using Uri = Android.Net.Uri;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden, Theme="@style/NoTitleBar")]
|
|
||||||
public class EntryActivity : Activity {
|
[Activity(Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden,
|
||||||
|
Theme = "@style/NoTitleBar")]
|
||||||
|
public class EntryActivity : Activity
|
||||||
|
{
|
||||||
public const String KeyEntry = "entry";
|
public const String KeyEntry = "entry";
|
||||||
public const String KeyRefreshPos = "refresh_pos";
|
public const String KeyRefreshPos = "refresh_pos";
|
||||||
public const String KeyCloseAfterCreate = "close_after_create";
|
public const String KeyCloseAfterCreate = "close_after_create";
|
||||||
|
|
||||||
|
protected PwEntry Entry = new PwEntry(true, true);
|
||||||
|
|
||||||
private static Typeface _passwordFont;
|
private static Typeface _passwordFont;
|
||||||
|
|
||||||
private bool _showPassword;
|
internal bool _showPassword;
|
||||||
private int _pos;
|
private int _pos;
|
||||||
|
|
||||||
private List<TextView> _protectedTextViews;
|
private List<TextView> _protectedTextViews;
|
||||||
|
|
||||||
|
private readonly Dictionary<string, List<IPopupMenuItem>> _popupMenuItems =
|
||||||
|
new Dictionary<string, List<IPopupMenuItem>>();
|
||||||
|
|
||||||
protected void SetEntryView() {
|
private readonly Dictionary<string, IStringView> _stringViews = new Dictionary<string, IStringView>();
|
||||||
|
private readonly List<PluginMenuOption> _pendingMenuOptions = new List<PluginMenuOption>();
|
||||||
|
private IMenu _menu;
|
||||||
|
|
||||||
|
protected void SetEntryView()
|
||||||
|
{
|
||||||
SetContentView(Resource.Layout.entry_view);
|
SetContentView(Resource.Layout.entry_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SetupEditButtons() {
|
protected void SetupEditButtons()
|
||||||
View edit = FindViewById(Resource.Id.entry_edit);
|
{
|
||||||
|
View edit = FindViewById(Resource.Id.entry_edit);
|
||||||
if (true)
|
if (true)
|
||||||
{
|
{
|
||||||
edit.Visibility = ViewStates.Visible;
|
edit.Visibility = ViewStates.Visible;
|
||||||
edit.Click += (sender, e) =>
|
edit.Click += (sender, e) =>
|
||||||
{
|
{
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
edit.Visibility = ViewStates.Gone;
|
edit.Visibility = ViewStates.Gone;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class PluginActionReceiver : BroadcastReceiver
|
||||||
|
{
|
||||||
|
private readonly EntryActivity _activity;
|
||||||
|
|
||||||
|
public PluginActionReceiver(EntryActivity activity)
|
||||||
|
{
|
||||||
|
_activity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
var pluginPackage = intent.GetStringExtra(Strings.ExtraSender);
|
||||||
|
if (new PluginDatabase(context).IsValidAccessToken(pluginPackage,
|
||||||
|
intent.GetStringExtra(Strings.ExtraAccessToken),
|
||||||
|
Strings.ScopeCurrentEntry))
|
||||||
|
{
|
||||||
|
if (intent.GetStringExtra(Strings.ExtraEntryId) != _activity.Entry.Uuid.ToHexString())
|
||||||
|
{
|
||||||
|
Kp2aLog.Log("received action for wrong entry " + intent.GetStringExtra(Strings.ExtraEntryId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_activity.AddPluginAction(pluginPackage,
|
||||||
|
intent.GetStringExtra(Strings.ExtraFieldId),
|
||||||
|
intent.GetStringExtra(Strings.ExtraActionDisplayText),
|
||||||
|
intent.GetIntExtra(Strings.ExtraActionIconResId, -1),
|
||||||
|
intent.GetBundleExtra(Strings.ExtraActionData));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Kp2aLog.Log("received invalid request. Plugin not authorized.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PluginFieldReceiver : BroadcastReceiver
|
||||||
|
{
|
||||||
|
private readonly EntryActivity _activity;
|
||||||
|
|
||||||
|
public PluginFieldReceiver(EntryActivity activity)
|
||||||
|
{
|
||||||
|
_activity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
if (intent.GetStringExtra(Strings.ExtraEntryId) != _activity.Entry.Uuid.ToHexString())
|
||||||
|
{
|
||||||
|
Kp2aLog.Log("received field for wrong entry " + intent.GetStringExtra(Strings.ExtraEntryId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!new PluginDatabase(context).IsValidAccessToken(intent.GetStringExtra(Strings.ExtraSender),
|
||||||
|
intent.GetStringExtra(Strings.ExtraAccessToken),
|
||||||
|
Strings.ScopeCurrentEntry))
|
||||||
|
{
|
||||||
|
Kp2aLog.Log("received field with invalid access token from " + intent.GetStringExtra(Strings.ExtraSender));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
string key = intent.GetStringExtra(Strings.ExtraFieldId);
|
||||||
|
string value = intent.GetStringExtra(Strings.ExtraFieldValue);
|
||||||
|
bool isProtected = intent.GetBooleanExtra(Strings.ExtraFieldProtected, false);
|
||||||
|
_activity.SetPluginField(key, value, isProtected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetPluginField(string key, string value, bool isProtected)
|
||||||
|
{
|
||||||
|
IStringView existingField;
|
||||||
|
if (_stringViews.TryGetValue(key, out existingField))
|
||||||
|
{
|
||||||
|
existingField.Text = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ViewGroup extraGroup = (ViewGroup) FindViewById(Resource.Id.extra_strings);
|
||||||
|
var view = CreateExtraSection(key, value, isProtected);
|
||||||
|
extraGroup.AddView(view.View);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddPluginAction(string pluginPackage, string fieldId, string displayText, int iconId, Bundle bundleExtra)
|
||||||
|
{
|
||||||
|
if (fieldId != null)
|
||||||
|
{
|
||||||
|
_popupMenuItems[fieldId].Add(new PluginPopupMenuItem(this, pluginPackage, fieldId, displayText, iconId, bundleExtra));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//we need to add an option to the menu.
|
||||||
|
//As it is not sure that OnCreateOptionsMenu was called yet, we cannot access _menu without a check:
|
||||||
|
|
||||||
|
Intent i = new Intent(Strings.ActionEntryActionSelected);
|
||||||
|
i.SetPackage(pluginPackage);
|
||||||
|
i.PutExtra(Strings.ExtraActionData, bundleExtra);
|
||||||
|
i.PutExtra(Strings.ExtraSender, PackageName);
|
||||||
|
|
||||||
|
var menuOption = new PluginMenuOption()
|
||||||
|
{
|
||||||
|
DisplayText = displayText,
|
||||||
|
Icon = PackageManager.GetResourcesForApplication(pluginPackage).GetDrawable(iconId),
|
||||||
|
Intent = i
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_menu != null)
|
||||||
|
{
|
||||||
|
AddMenuOption(menuOption);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lock (_pendingMenuOptions)
|
||||||
|
{
|
||||||
|
_pendingMenuOptions.Add(menuOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddMenuOption(PluginMenuOption menuOption)
|
||||||
|
{
|
||||||
|
var menuItem = _menu.Add(menuOption.DisplayText);
|
||||||
|
menuItem.SetIcon(menuOption.Icon);
|
||||||
|
menuItem.SetIntent(menuOption.Intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool OnCreateOptionsMenu(IMenu menu)
|
||||||
|
{
|
||||||
|
_menu = menu;
|
||||||
|
base.OnCreateOptionsMenu(menu);
|
||||||
|
|
||||||
|
MenuInflater inflater = MenuInflater;
|
||||||
|
inflater.Inflate(Resource.Menu.entry, menu);
|
||||||
|
|
||||||
|
lock (_pendingMenuOptions)
|
||||||
|
{
|
||||||
|
foreach (var option in _pendingMenuOptions)
|
||||||
|
AddMenuOption(option);
|
||||||
|
_pendingMenuOptions.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
UpdateTogglePasswordMenu();
|
||||||
|
|
||||||
|
IMenuItem gotoUrl = menu.FindItem(Resource.Id.menu_goto_url);
|
||||||
|
//Disabled IMenuItem copyUser = menu.FindItem(Resource.Id.menu_copy_user);
|
||||||
|
//Disabled IMenuItem copyPass = menu.FindItem(Resource.Id.menu_copy_pass);
|
||||||
|
|
||||||
|
// In API >= 11 onCreateOptionsMenu may be called before onCreate completes
|
||||||
|
// so _entry may not be set
|
||||||
|
if (Entry == null)
|
||||||
|
{
|
||||||
|
gotoUrl.SetVisible(false);
|
||||||
|
//Disabled copyUser.SetVisible(false);
|
||||||
|
//Disabled copyPass.SetVisible(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String url = Entry.Strings.ReadSafe(PwDefs.UrlField);
|
||||||
|
if (String.IsNullOrEmpty(url))
|
||||||
|
{
|
||||||
|
// disable button if url is not available
|
||||||
|
gotoUrl.SetVisible(false);
|
||||||
|
}
|
||||||
|
if (String.IsNullOrEmpty(Entry.Strings.ReadSafe(PwDefs.UserNameField)))
|
||||||
|
{
|
||||||
|
// disable button if username is not available
|
||||||
|
//Disabled copyUser.SetVisible(false);
|
||||||
|
}
|
||||||
|
if (String.IsNullOrEmpty(Entry.Strings.ReadSafe(PwDefs.PasswordField)))
|
||||||
|
{
|
||||||
|
// disable button if password is not available
|
||||||
|
//Disabled copyPass.SetVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool OnOptionsItemSelected(IMenuItem item)
|
||||||
|
{
|
||||||
|
//check if this is a plugin action
|
||||||
|
if ((item.Intent != null) && (item.Intent.Action == Strings.ActionEntryActionSelected))
|
||||||
|
{
|
||||||
|
//yes. let the plugin handle the click:
|
||||||
|
SendBroadcast(item.Intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (item.ItemId)
|
||||||
|
{
|
||||||
|
case Resource.Id.menu_donate:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Util.GotoDonateUrl(this);
|
||||||
|
}
|
||||||
|
catch (ActivityNotFoundException)
|
||||||
|
{
|
||||||
|
Toast.MakeText(this, Resource.String.error_failed_to_launch_link, ToastLength.Long).Show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
case Resource.Id.menu_toggle_pass:
|
||||||
|
if (_showPassword)
|
||||||
|
{
|
||||||
|
item.SetTitle(Resource.String.show_password);
|
||||||
|
_showPassword = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.SetTitle(Resource.String.menu_hide_password);
|
||||||
|
_showPassword = true;
|
||||||
|
}
|
||||||
|
SetPasswordStyle();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Resource.Id.menu_goto_url:
|
||||||
|
string url = _stringViews[PwDefs.UrlField].Text;
|
||||||
|
if (url == null) return false;
|
||||||
|
|
||||||
|
// Default http:// if no protocol specified
|
||||||
|
if (!url.Contains("://"))
|
||||||
|
{
|
||||||
|
url = "http://" + url;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (ActivityNotFoundException)
|
||||||
|
{
|
||||||
|
Toast.MakeText(this, Resource.String.no_url_handler, ToastLength.Long).Show();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
/* TODO: required?
|
||||||
|
case Resource.Id.menu_copy_user:
|
||||||
|
timeoutCopyToClipboard(_entry.Strings.ReadSafe (PwDefs.UserNameField));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Resource.Id.menu_copy_pass:
|
||||||
|
timeoutCopyToClipboard(_entry.Strings.ReadSafe (PwDefs.UserNameField));
|
||||||
|
return true;
|
||||||
|
*/
|
||||||
|
case Resource.Id.menu_rate:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (ActivityNotFoundException)
|
||||||
|
{
|
||||||
|
Toast.MakeText(this, Resource.String.no_url_handler, ToastLength.Long).Show();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case Resource.Id.menu_suggest_improvements:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (ActivityNotFoundException)
|
||||||
|
{
|
||||||
|
Toast.MakeText(this, Resource.String.no_url_handler, ToastLength.Long).Show();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case Resource.Id.menu_lock:
|
||||||
|
return true;
|
||||||
|
case Resource.Id.menu_translate:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (ActivityNotFoundException)
|
||||||
|
{
|
||||||
|
Toast.MakeText(this, Resource.String.no_url_handler, ToastLength.Long).Show();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case Android.Resource.Id.Home:
|
||||||
|
//Currently the action bar only displays the home button when we come from a previous activity.
|
||||||
|
//So we can simply Finish. See this page for information on how to do this in more general (future?) cases:
|
||||||
|
//http://developer.android.com/training/implementing-navigation/ancestral.html
|
||||||
|
Finish();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return base.OnOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override void OnCreate(Bundle savedInstanceState)
|
protected override void OnCreate(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
|
|
||||||
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
|
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
|
||||||
|
|
||||||
long usageCount = prefs.GetLong(GetString(Resource.String.UsageCount_key), 0);
|
long usageCount = prefs.GetLong(GetString(Resource.String.UsageCount_key), 0);
|
||||||
|
|
||||||
ISharedPreferencesEditor edit = prefs.Edit();
|
ISharedPreferencesEditor edit = prefs.Edit();
|
||||||
edit.PutLong(GetString(Resource.String.UsageCount_key), usageCount+1);
|
edit.PutLong(GetString(Resource.String.UsageCount_key), usageCount + 1);
|
||||||
edit.Commit();
|
edit.Commit();
|
||||||
|
|
||||||
_showPassword = ! prefs.GetBoolean(GetString(Resource.String.maskpass_key), Resources.GetBoolean(Resource.Boolean.maskpass_default));
|
_showPassword =
|
||||||
|
!prefs.GetBoolean(GetString(Resource.String.maskpass_key), Resources.GetBoolean(Resource.Boolean.maskpass_default));
|
||||||
|
|
||||||
|
Entry.Strings.Set(PwDefs.UserNameField, new ProtectedString(false, "philipp "));
|
||||||
|
Entry.Strings.Set(PwDefs.PasswordField, new ProtectedString(true, "password value"));
|
||||||
|
Entry.Strings.Set(PwDefs.UrlField, new ProtectedString(false, "https://www.google.com"));
|
||||||
|
Entry.Strings.Set("field header", new ProtectedString(true, "protected field value"));
|
||||||
|
Entry.Strings.Set("public field header", new ProtectedString(false, "public field value"));
|
||||||
|
|
||||||
base.OnCreate(savedInstanceState);
|
base.OnCreate(savedInstanceState);
|
||||||
SetEntryView();
|
SetEntryView();
|
||||||
|
|
||||||
FillData(false);
|
FillData();
|
||||||
|
|
||||||
SetupEditButtons();
|
SetupEditButtons();
|
||||||
|
|
||||||
|
RegisterReceiver(new PluginActionReceiver(this), new IntentFilter(Strings.ActionAddEntryAction));
|
||||||
|
RegisterReceiver(new PluginFieldReceiver(this), new IntentFilter(Strings.ActionSetEntryField));
|
||||||
|
|
||||||
|
new Thread(NotifyPluginsOnOpen).Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NotifyPluginsOnOpen()
|
||||||
|
{
|
||||||
|
App.Kp2A.GetDb().SetEntry(Entry);
|
||||||
|
|
||||||
|
Intent i = new Intent(Strings.ActionOpenEntry);
|
||||||
|
i.PutExtra(Strings.ExtraSender, PackageName);
|
||||||
|
PluginHost.AddEntryToIntent(i, Entry);
|
||||||
|
|
||||||
|
foreach (var plugin in new PluginDatabase(this).GetPluginsWithAcceptedScope(Strings.ScopeCurrentEntry))
|
||||||
|
{
|
||||||
|
i.SetPackage(plugin);
|
||||||
|
SendBroadcast(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CompleteOnCreate()
|
public void CompleteOnCreate()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private String getDateTime(DateTime dt) {
|
private String getDateTime(DateTime dt)
|
||||||
return dt.ToString ("g", CultureInfo.CurrentUICulture);
|
{
|
||||||
|
return dt.ToString("g", CultureInfo.CurrentUICulture);
|
||||||
}
|
}
|
||||||
|
|
||||||
String concatTags(List<string> tags)
|
private String concatTags(List<string> tags)
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
foreach (string tag in tags)
|
foreach (string tag in tags)
|
||||||
@ -113,70 +448,98 @@ namespace keepass2android
|
|||||||
sb.Append(", ");
|
sb.Append(", ");
|
||||||
}
|
}
|
||||||
if (tags.Count > 0)
|
if (tags.Count > 0)
|
||||||
sb.Remove(sb.Length-2,2);
|
sb.Remove(sb.Length - 2, 2);
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PopulateExtraStrings(bool trimList)
|
private void PopulateExtraStrings()
|
||||||
{
|
{
|
||||||
ViewGroup extraGroup = (ViewGroup)FindViewById(Resource.Id.extra_strings);
|
ViewGroup extraGroup = (ViewGroup) FindViewById(Resource.Id.extra_strings);
|
||||||
if (trimList)
|
foreach (var pair in Entry.Strings.Where(pair => !PwDefs.IsStandardField(pair.Key)).OrderBy(pair => pair.Key))
|
||||||
{
|
{
|
||||||
extraGroup.RemoveAllViews();
|
var stringView = CreateExtraSection(pair.Key, pair.Value.ReadString(), pair.Value.IsProtected);
|
||||||
|
extraGroup.AddView(stringView.View);
|
||||||
}
|
}
|
||||||
bool hasExtraFields = false;
|
|
||||||
foreach (var view in from pair in new Dictionary<string, string>() { { "Field header", "field value" }, { "another header", "_aiaeiae" } }
|
|
||||||
orderby pair.Key
|
|
||||||
select CreateEditSection(pair.Key, pair.Value, true))
|
|
||||||
{
|
|
||||||
extraGroup.AddView(view);
|
|
||||||
hasExtraFields = true;
|
|
||||||
}
|
|
||||||
FindViewById(Resource.Id.entry_extra_strings_label).Visibility = hasExtraFields ? ViewStates.Visible : ViewStates.Gone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
View CreateEditSection(string key, string value, bool isProtected)
|
private ExtraStringView CreateExtraSection(string key, string value, bool isProtected)
|
||||||
{
|
{
|
||||||
LinearLayout layout = new LinearLayout(this, null) {Orientation = Orientation.Vertical};
|
LinearLayout layout = new LinearLayout(this, null) {Orientation = Orientation.Vertical};
|
||||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
|
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FillParent,
|
||||||
layoutParams.SetMargins(10,0,0,0);
|
ViewGroup.LayoutParams.WrapContent);
|
||||||
|
|
||||||
layout.LayoutParameters = layoutParams;
|
layout.LayoutParameters = layoutParams;
|
||||||
View viewInflated = LayoutInflater.Inflate(Resource.Layout.entry_extrastring_title,null);
|
View viewInflated = LayoutInflater.Inflate(Resource.Layout.entry_extrastring_title, null);
|
||||||
TextView keyView = (TextView)viewInflated;
|
TextView keyView = viewInflated.FindViewById<TextView>(Resource.Id.entry_title);
|
||||||
if (key != null)
|
if (key != null)
|
||||||
keyView.Text = key;
|
keyView.Text = key;
|
||||||
|
|
||||||
layout.AddView(keyView);
|
layout.AddView(viewInflated);
|
||||||
TextView valueView = (TextView)LayoutInflater.Inflate(Resource.Layout.entry_extrastring_value, null);
|
RelativeLayout valueViewContainer =
|
||||||
|
(RelativeLayout) LayoutInflater.Inflate(Resource.Layout.entry_extrastring_value, null);
|
||||||
|
var valueView = valueViewContainer.FindViewById<TextView>(Resource.Id.entry_extra);
|
||||||
if (value != null)
|
if (value != null)
|
||||||
valueView.Text = value;
|
valueView.Text = value;
|
||||||
SetPasswordTypeface(valueView);
|
SetPasswordTypeface(valueView);
|
||||||
if (isProtected)
|
if (isProtected)
|
||||||
|
{
|
||||||
RegisterProtectedTextView(valueView);
|
RegisterProtectedTextView(valueView);
|
||||||
|
valueView.TransformationMethod = PasswordTransformationMethod.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.AddView(valueViewContainer);
|
||||||
|
var stringView = new ExtraStringView(layout, valueView, keyView);
|
||||||
|
|
||||||
|
_stringViews.Add(key, stringView);
|
||||||
|
RegisterTextPopup(valueViewContainer, valueViewContainer.FindViewById(Resource.Id.extra_vdots), key, isProtected);
|
||||||
|
|
||||||
|
return stringView;
|
||||||
|
|
||||||
if ((int)Build.VERSION.SdkInt >= 11)
|
|
||||||
valueView.SetTextIsSelectable(true);
|
|
||||||
layout.AddView(valueView);
|
|
||||||
return layout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<IPopupMenuItem> RegisterPopup(string popupKey, View clickView, View anchorView)
|
||||||
|
{
|
||||||
|
clickView.Click += (sender, args) =>
|
||||||
|
{
|
||||||
|
ShowPopup(anchorView, popupKey);
|
||||||
|
};
|
||||||
|
_popupMenuItems[popupKey] = new List<IPopupMenuItem>();
|
||||||
|
return _popupMenuItems[popupKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void RegisterProtectedTextView(TextView protectedTextView)
|
private void RegisterProtectedTextView(TextView protectedTextView)
|
||||||
{
|
{
|
||||||
_protectedTextViews.Add(protectedTextView);
|
_protectedTextViews.Add(protectedTextView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PopulateBinaries(bool trimList)
|
private void PopulateBinaries()
|
||||||
{
|
{
|
||||||
ViewGroup binariesGroup = (ViewGroup)FindViewById(Resource.Id.binaries);
|
ViewGroup binariesGroup = (ViewGroup) FindViewById(Resource.Id.binaries);
|
||||||
if (trimList)
|
foreach (KeyValuePair<string, string> pair in new Dictionary<string, string>() {{"abc", ""}, {"test.png", "uia"}})
|
||||||
{
|
|
||||||
binariesGroup.RemoveAllViews();
|
|
||||||
}
|
|
||||||
foreach (KeyValuePair<string, string> pair in new Dictionary<string, string>() { {"abc",""}, {"test.png","uia"} })
|
|
||||||
{
|
{
|
||||||
String key = pair.Key;
|
String key = pair.Key;
|
||||||
|
|
||||||
|
|
||||||
|
RelativeLayout valueViewContainer =
|
||||||
|
(RelativeLayout) LayoutInflater.Inflate(Resource.Layout.entry_extrastring_value, null);
|
||||||
|
var valueView = valueViewContainer.FindViewById<TextView>(Resource.Id.entry_extra);
|
||||||
|
if (key != null)
|
||||||
|
valueView.Text = key;
|
||||||
|
|
||||||
|
string popupKey = Strings.PrefixBinary + key;
|
||||||
|
|
||||||
|
var itemList = RegisterPopup(popupKey, valueViewContainer, valueViewContainer.FindViewById(Resource.Id.extra_vdots));
|
||||||
|
itemList.Add(new WriteBinaryToFilePopupItem(key, this));
|
||||||
|
itemList.Add(new OpenBinaryPopupItem(key, this));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
binariesGroup.AddView(valueViewContainer);
|
||||||
|
/*
|
||||||
Button binaryButton = new Button(this);
|
Button binaryButton = new Button(this);
|
||||||
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
|
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
|
||||||
binaryButton.Text = key;
|
binaryButton.Text = key;
|
||||||
@ -206,8 +569,8 @@ namespace keepass2android
|
|||||||
|
|
||||||
};
|
};
|
||||||
binariesGroup.AddView(binaryButton,layoutParams);
|
binariesGroup.AddView(binaryButton,layoutParams);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
FindViewById(Resource.Id.entry_binaries_label).Visibility = true ? ViewStates.Visible : ViewStates.Gone;
|
FindViewById(Resource.Id.entry_binaries_label).Visibility = true ? ViewStates.Visible : ViewStates.Gone;
|
||||||
}
|
}
|
||||||
@ -217,7 +580,8 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
String type = null;
|
String type = null;
|
||||||
String extension = MimeTypeMap.GetFileExtensionFromUrl(url);
|
String extension = MimeTypeMap.GetFileExtensionFromUrl(url);
|
||||||
if (extension != null) {
|
if (extension != null)
|
||||||
|
{
|
||||||
MimeTypeMap mime = MimeTypeMap.Singleton;
|
MimeTypeMap mime = MimeTypeMap.Singleton;
|
||||||
type = mime.GetMimeTypeFromExtension(extension);
|
type = mime.GetMimeTypeFromExtension(extension);
|
||||||
}
|
}
|
||||||
@ -229,94 +593,182 @@ namespace keepass2android
|
|||||||
base.OnBackPressed();
|
base.OnBackPressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void FillData(bool trimList)
|
protected void FillData()
|
||||||
{
|
{
|
||||||
_protectedTextViews = new List<TextView>();
|
_protectedTextViews = new List<TextView>();
|
||||||
ImageView iv = (ImageView)FindViewById(Resource.Id.entry_icon);
|
ImageView iv = (ImageView) FindViewById(Resource.Id.entry_icon);
|
||||||
if (iv != null)
|
if (iv != null)
|
||||||
{
|
{
|
||||||
iv.SetImageDrawable(Resources.GetDrawable(Resource.Drawable.ic00));
|
iv.SetImageDrawable(Resources.GetDrawable(Resource.Drawable.ic00));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ActionBar.Title = "Entry title";
|
ActionBar.Title = "Entry title";
|
||||||
ActionBar.SetDisplayHomeAsUpEnabled(true);
|
ActionBar.SetDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
PopulateText(Resource.Id.entry_user_name, Resource.Id.entry_user_name_label, "user name");
|
|
||||||
|
|
||||||
PopulateText(Resource.Id.entry_url, Resource.Id.entry_url_label, "www.google.com");
|
PopulateStandardText(Resource.Id.entry_user_name, Resource.Id.entryfield_container_username, PwDefs.UserNameField);
|
||||||
PopulateText(Resource.Id.entry_password, Resource.Id.entry_password_label, "my password");
|
PopulateStandardText(Resource.Id.entry_url, Resource.Id.entryfield_container_url, PwDefs.UrlField);
|
||||||
|
PopulateStandardText(Resource.Id.entry_password, Resource.Id.entryfield_container_password, PwDefs.PasswordField);
|
||||||
RegisterProtectedTextView(FindViewById<TextView>(Resource.Id.entry_password));
|
RegisterProtectedTextView(FindViewById<TextView>(Resource.Id.entry_password));
|
||||||
SetPasswordTypeface(FindViewById<TextView>(Resource.Id.entry_password));
|
SetPasswordTypeface(FindViewById<TextView>(Resource.Id.entry_password));
|
||||||
|
|
||||||
|
|
||||||
PopulateText(Resource.Id.entry_created, Resource.Id.entry_created_label, getDateTime(DateTime.Now));
|
|
||||||
PopulateText(Resource.Id.entry_modified, Resource.Id.entry_modified_label, getDateTime(DateTime.Now));
|
|
||||||
|
|
||||||
if (true)
|
|
||||||
{
|
|
||||||
FindViewById(Resource.Id.entry_expires).Visibility = ViewStates.Visible;
|
|
||||||
FindViewById(Resource.Id.entry_expires_label).Visibility = ViewStates.Visible;
|
|
||||||
|
|
||||||
PopulateText(Resource.Id.entry_expires, Resource.Id.entry_expires_label, getDateTime(DateTime.Now));
|
|
||||||
|
|
||||||
}
|
RegisterTextPopup(FindViewById<RelativeLayout>(Resource.Id.username_container),
|
||||||
|
FindViewById(Resource.Id.username_vdots), PwDefs.UserNameField);
|
||||||
|
RegisterTextPopup(FindViewById<RelativeLayout>(Resource.Id.url_container),
|
||||||
|
FindViewById(Resource.Id.url_vdots), PwDefs.UrlField)
|
||||||
|
.Add(new GotoUrlMenuItem(this));
|
||||||
|
RegisterTextPopup(FindViewById<RelativeLayout>(Resource.Id.password_container),
|
||||||
|
FindViewById(Resource.Id.password_vdots), PwDefs.PasswordField);
|
||||||
|
|
||||||
|
|
||||||
|
PopulateText(Resource.Id.entry_created, Resource.Id.entryfield_container_created, getDateTime(Entry.CreationTime));
|
||||||
|
PopulateText(Resource.Id.entry_modified, Resource.Id.entryfield_container_modified, getDateTime(Entry.LastModificationTime));
|
||||||
|
|
||||||
|
if (Entry.Expires)
|
||||||
|
{
|
||||||
|
PopulateText(Resource.Id.entry_expires, Resource.Id.entryfield_container_expires, getDateTime(Entry.ExpiryTime));
|
||||||
|
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FindViewById(Resource.Id.entry_expires).Visibility = ViewStates.Gone;
|
PopulateText(Resource.Id.entry_expires, Resource.Id.entryfield_container_expires, null);
|
||||||
FindViewById(Resource.Id.entry_expires_label).Visibility = ViewStates.Gone;
|
|
||||||
}
|
}
|
||||||
PopulateText(Resource.Id.entry_comment, Resource.Id.entry_comment_label, "some text about this entry");
|
PopulateStandardText(Resource.Id.entry_comment, Resource.Id.entryfield_container_comment, PwDefs.NotesField);
|
||||||
|
PopulateText(Resource.Id.entry_tags, Resource.Id.entryfield_container_tags, concatTags(Entry.Tags));
|
||||||
|
PopulateText(Resource.Id.entry_override_url, Resource.Id.entryfield_container_overrideurl, Entry.OverrideUrl);
|
||||||
|
|
||||||
PopulateText(Resource.Id.entry_tags, Resource.Id.entry_tags_label, "bla; blubb; blablubb");
|
PopulateExtraStrings();
|
||||||
|
|
||||||
PopulateExtraStrings(trimList);
|
PopulateBinaries();
|
||||||
|
|
||||||
PopulateBinaries(trimList);
|
|
||||||
|
|
||||||
SetPasswordStyle();
|
SetPasswordStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
|
||||||
|
{
|
||||||
|
base.OnActivityResult(requestCode, resultCode, data);
|
||||||
|
if (resultCode == /*TODO*/ 0)
|
||||||
|
{
|
||||||
|
if (resultCode == /*TODO*/ 0)
|
||||||
|
{
|
||||||
|
RequiresRefresh();
|
||||||
|
}
|
||||||
|
Recreate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDestroy()
|
||||||
|
{
|
||||||
|
NotifyPluginsOnClose();
|
||||||
|
base.OnDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NotifyPluginsOnClose()
|
||||||
|
{
|
||||||
|
Intent i = new Intent(Strings.ActionCloseEntryView);
|
||||||
|
i.PutExtra(Strings.ExtraSender, PackageName);
|
||||||
|
foreach (var plugin in new PluginDatabase(this).GetPluginsWithAcceptedScope(Strings.ScopeCurrentEntry))
|
||||||
|
{
|
||||||
|
i.SetPackage(plugin);
|
||||||
|
SendBroadcast(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private List<IPopupMenuItem> RegisterTextPopup(View container, View anchor, string fieldKey)
|
||||||
|
{
|
||||||
|
return RegisterTextPopup(container, anchor, fieldKey, Entry.Strings.GetSafe(fieldKey).IsProtected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<IPopupMenuItem> RegisterTextPopup(View container, View anchor, string fieldKey, bool isProtected)
|
||||||
|
{
|
||||||
|
string popupKey = Strings.PrefixString + fieldKey;
|
||||||
|
var popupItems = RegisterPopup(
|
||||||
|
popupKey,
|
||||||
|
container,
|
||||||
|
anchor);
|
||||||
|
popupItems.Add(new CopyToClipboardPopupMenuIcon(this, _stringViews[fieldKey]));
|
||||||
|
if (isProtected)
|
||||||
|
popupItems.Add(new ToggleVisibilityPopupMenuItem(this));
|
||||||
|
return popupItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void ShowPopup(View anchor, string popupKey)
|
||||||
|
{
|
||||||
|
//PopupMenu popupMenu = new PopupMenu(this, FindViewById(Resource.Id.entry_user_name));
|
||||||
|
PopupMenu popupMenu = new PopupMenu(this, anchor);
|
||||||
|
|
||||||
|
AccessManager.PreparePopup(popupMenu);
|
||||||
|
int itemId = 0;
|
||||||
|
foreach (IPopupMenuItem popupItem in _popupMenuItems[popupKey])
|
||||||
|
{
|
||||||
|
popupMenu.Menu.Add(0, itemId, 0, popupItem.Text)
|
||||||
|
.SetIcon(popupItem.Icon);
|
||||||
|
itemId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
popupMenu.MenuItemClick += delegate(object sender, PopupMenu.MenuItemClickEventArgs args)
|
||||||
|
{
|
||||||
|
_popupMenuItems[popupKey][args.Item.ItemId].HandleClick();
|
||||||
|
};
|
||||||
|
popupMenu.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowPopup(int resAnchor, string popupKey)
|
||||||
|
{
|
||||||
|
ShowPopup(FindViewById(resAnchor), popupKey);
|
||||||
|
}
|
||||||
|
|
||||||
private void SetPasswordTypeface(TextView textView)
|
private void SetPasswordTypeface(TextView textView)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopulateText(int viewId, int headerViewId,int resId) {
|
private void PopulateText(int viewId, int containerViewId, int resId)
|
||||||
View header = FindViewById(headerViewId);
|
{
|
||||||
TextView tv = (TextView)FindViewById(viewId);
|
View header = FindViewById(containerViewId);
|
||||||
|
TextView tv = (TextView) FindViewById(viewId);
|
||||||
|
|
||||||
header.Visibility = tv.Visibility = ViewStates.Visible;
|
header.Visibility = tv.Visibility = ViewStates.Visible;
|
||||||
tv.SetText (resId);
|
tv.SetText(resId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopulateText(int viewId, int headerViewId, String text)
|
private void PopulateText(int viewId, int containerViewId, String text)
|
||||||
{
|
{
|
||||||
View header = FindViewById(headerViewId);
|
View container = FindViewById(containerViewId);
|
||||||
TextView tv = (TextView)FindViewById(viewId);
|
TextView tv = (TextView) FindViewById(viewId);
|
||||||
if (String.IsNullOrEmpty(text))
|
if (String.IsNullOrEmpty(text))
|
||||||
{
|
{
|
||||||
header.Visibility = tv.Visibility = ViewStates.Gone;
|
container.Visibility = tv.Visibility = ViewStates.Gone;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
header.Visibility = tv.Visibility = ViewStates.Visible;
|
container.Visibility = tv.Visibility = ViewStates.Visible;
|
||||||
tv.Text = text;
|
tv.Text = text;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequiresRefresh ()
|
private void PopulateStandardText(int viewId, int containerViewId, String key)
|
||||||
{
|
{
|
||||||
Intent ret = new Intent ();
|
PopulateText(viewId, containerViewId, Entry.Strings.ReadSafe(key));
|
||||||
ret.PutExtra (KeyRefreshPos, _pos);
|
_stringViews.Add(key, new StandardStringView(viewId, containerViewId, this));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RequiresRefresh()
|
||||||
|
{
|
||||||
private void SetPasswordStyle() {
|
Intent ret = new Intent();
|
||||||
|
ret.PutExtra(KeyRefreshPos, _pos);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void SetPasswordStyle()
|
||||||
|
{
|
||||||
foreach (TextView password in _protectedTextViews)
|
foreach (TextView password in _protectedTextViews)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -330,12 +782,13 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnResume()
|
protected override void OnResume()
|
||||||
{
|
{
|
||||||
|
|
||||||
base.OnResume();
|
base.OnResume();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// brings up a dialog asking the user whether he wants to add the given URL to the entry for automatic finding
|
/// brings up a dialog asking the user whether he wants to add the given URL to the entry for automatic finding
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -344,24 +797,50 @@ namespace keepass2android
|
|||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.SetTitle(GetString(Resource.String.AddUrlToEntryDialog_title));
|
builder.SetTitle(GetString(Resource.String.AddUrlToEntryDialog_title));
|
||||||
|
|
||||||
builder.SetMessage(GetString(Resource.String.AddUrlToEntryDialog_text, new Java.Lang.Object[] { url } ));
|
builder.SetMessage(GetString(Resource.String.AddUrlToEntryDialog_text, new Java.Lang.Object[] {url}));
|
||||||
|
|
||||||
builder.SetPositiveButton(GetString(Resource.String.yes), (dlgSender, dlgEvt) =>
|
builder.SetPositiveButton(GetString(Resource.String.yes), (dlgSender, dlgEvt) =>
|
||||||
{
|
{
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.SetNegativeButton(GetString(Resource.String.no), (dlgSender, dlgEvt) =>
|
builder.SetNegativeButton(GetString(Resource.String.no), (dlgSender, dlgEvt) =>
|
||||||
{
|
{
|
||||||
CompleteOnCreate();
|
CompleteOnCreate();
|
||||||
});
|
});
|
||||||
|
|
||||||
Dialog dialog = builder.Create();
|
Dialog dialog = builder.Create();
|
||||||
dialog.Show();
|
dialog.Show();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ToggleVisibility()
|
||||||
|
{
|
||||||
|
_showPassword = !_showPassword;
|
||||||
|
SetPasswordStyle();
|
||||||
|
UpdateTogglePasswordMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Android.Net.Uri WriteBinaryToFile(string key, bool writeToCacheDirectory)
|
||||||
|
{
|
||||||
|
return Android.Net.Uri.Empty;
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTogglePasswordMenu()
|
||||||
|
{
|
||||||
|
//todo use real method
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GotoUrl()
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenBinaryFile(Uri newUri)
|
||||||
|
{
|
||||||
|
Toast.MakeText(this, "opening file TODO", ToastLength.Short).Show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
44
src/PluginHostTest/EntryActivityClasses/ExtraStringView.cs
Normal file
44
src/PluginHostTest/EntryActivityClasses/ExtraStringView.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using Android.Views;
|
||||||
|
using Android.Widget;
|
||||||
|
|
||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
internal class ExtraStringView : IStringView
|
||||||
|
{
|
||||||
|
private readonly View _container;
|
||||||
|
private readonly TextView _valueView;
|
||||||
|
private readonly TextView _keyView;
|
||||||
|
|
||||||
|
public ExtraStringView(LinearLayout container, TextView valueView, TextView keyView)
|
||||||
|
{
|
||||||
|
_container = container;
|
||||||
|
_valueView = valueView;
|
||||||
|
_keyView = keyView;
|
||||||
|
}
|
||||||
|
|
||||||
|
public View View
|
||||||
|
{
|
||||||
|
get { return _container; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get { return _valueView.Text; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (String.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
_valueView.Visibility = ViewStates.Gone;
|
||||||
|
_keyView.Visibility = ViewStates.Gone;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_valueView.Visibility = ViewStates.Visible;
|
||||||
|
_keyView.Visibility = ViewStates.Visible;
|
||||||
|
_valueView.Text = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
112
src/PluginHostTest/EntryActivityClasses/IPopupMenuItem.cs
Normal file
112
src/PluginHostTest/EntryActivityClasses/IPopupMenuItem.cs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
using System;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.Graphics.Drawables;
|
||||||
|
using KeePassLib;
|
||||||
|
using PluginHostTest;
|
||||||
|
|
||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
internal interface IPopupMenuItem
|
||||||
|
{
|
||||||
|
Drawable Icon { get; }
|
||||||
|
String Text { get; }
|
||||||
|
|
||||||
|
void HandleClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
class GotoUrlMenuItem : IPopupMenuItem
|
||||||
|
{
|
||||||
|
private readonly EntryActivity _ctx;
|
||||||
|
|
||||||
|
public GotoUrlMenuItem(EntryActivity ctx)
|
||||||
|
{
|
||||||
|
_ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable Icon
|
||||||
|
{
|
||||||
|
get { return _ctx.Resources.GetDrawable(Android.Resource.Drawable.IcMenuUpload); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get { return _ctx.Resources.GetString(Resource.String.menu_url); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleClick()
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
_ctx.GotoUrl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ToggleVisibilityPopupMenuItem : IPopupMenuItem
|
||||||
|
{
|
||||||
|
private readonly EntryActivity _activity;
|
||||||
|
|
||||||
|
|
||||||
|
public ToggleVisibilityPopupMenuItem(EntryActivity activity)
|
||||||
|
{
|
||||||
|
_activity = activity;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable Icon
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
//return new TextDrawable("\uF06E", _activity);
|
||||||
|
return _activity.Resources.GetDrawable(Resource.Drawable.ic_action_eye_open);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _activity.Resources.GetString(
|
||||||
|
_activity._showPassword ?
|
||||||
|
Resource.String.menu_hide_password
|
||||||
|
: Resource.String.show_password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void HandleClick()
|
||||||
|
{
|
||||||
|
_activity.ToggleVisibility();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CopyToClipboardPopupMenuIcon : IPopupMenuItem
|
||||||
|
{
|
||||||
|
private readonly Context _context;
|
||||||
|
private readonly IStringView _stringView;
|
||||||
|
|
||||||
|
public CopyToClipboardPopupMenuIcon(Context context, IStringView stringView)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_stringView = stringView;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable Icon
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _context.Resources.GetDrawable(Resource.Drawable.ic_menu_copy_holo_light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
//TODO localize
|
||||||
|
get { return "Copy to clipboard"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void HandleClick()
|
||||||
|
{
|
||||||
|
CopyToClipboardService.CopyValueToClipboardWithTimeout(_context, _stringView.Text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
src/PluginHostTest/EntryActivityClasses/IStringView.cs
Normal file
7
src/PluginHostTest/EntryActivityClasses/IStringView.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
internal interface IStringView
|
||||||
|
{
|
||||||
|
string Text { set; get; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
using Android.Graphics.Drawables;
|
||||||
|
using PluginHostTest;
|
||||||
|
|
||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
internal class OpenBinaryPopupItem : IPopupMenuItem
|
||||||
|
{
|
||||||
|
private readonly string _key;
|
||||||
|
private readonly EntryActivity _entryActivity;
|
||||||
|
|
||||||
|
public OpenBinaryPopupItem(string key, EntryActivity entryActivity)
|
||||||
|
{
|
||||||
|
_key = key;
|
||||||
|
_entryActivity = entryActivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable Icon
|
||||||
|
{
|
||||||
|
get { return _entryActivity.Resources.GetDrawable(Android.Resource.Drawable.IcMenuShare); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get { return _entryActivity.Resources.GetString(Resource.String.SaveAttachmentDialog_open); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleClick()
|
||||||
|
{
|
||||||
|
Android.Net.Uri newUri = _entryActivity.WriteBinaryToFile(_key, true);
|
||||||
|
if (newUri != null)
|
||||||
|
{
|
||||||
|
_entryActivity.OpenBinaryFile(newUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/PluginHostTest/EntryActivityClasses/PluginMenuOption.cs
Normal file
14
src/PluginHostTest/EntryActivityClasses/PluginMenuOption.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using Android.Content;
|
||||||
|
using Android.Graphics.Drawables;
|
||||||
|
|
||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
class PluginMenuOption
|
||||||
|
{
|
||||||
|
public string DisplayText { get; set; }
|
||||||
|
|
||||||
|
public Drawable Icon { get; set; }
|
||||||
|
|
||||||
|
public Intent Intent { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
using Android.Content;
|
||||||
|
using Android.Graphics.Drawables;
|
||||||
|
using Android.OS;
|
||||||
|
using Keepass2android.Pluginsdk;
|
||||||
|
|
||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
class PluginPopupMenuItem : IPopupMenuItem
|
||||||
|
{
|
||||||
|
private readonly Context _ctx;
|
||||||
|
private readonly string _pluginPackage;
|
||||||
|
private readonly string _fieldId;
|
||||||
|
private readonly string _displayText;
|
||||||
|
private readonly int _iconId;
|
||||||
|
private readonly Bundle _bundleExtra;
|
||||||
|
|
||||||
|
public PluginPopupMenuItem(Context ctx, string pluginPackage, string fieldId, string displayText, int iconId, Bundle bundleExtra)
|
||||||
|
{
|
||||||
|
_ctx = ctx;
|
||||||
|
_pluginPackage = pluginPackage;
|
||||||
|
_fieldId = fieldId;
|
||||||
|
_displayText = displayText;
|
||||||
|
_iconId = iconId;
|
||||||
|
_bundleExtra = bundleExtra;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable Icon
|
||||||
|
{
|
||||||
|
get { return _ctx.PackageManager.GetResourcesForApplication(_pluginPackage).GetDrawable(_iconId); }
|
||||||
|
}
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get { return _displayText; }
|
||||||
|
}
|
||||||
|
public void HandleClick()
|
||||||
|
{
|
||||||
|
Intent i = new Intent(Strings.ActionEntryActionSelected);
|
||||||
|
i.SetPackage(_pluginPackage);
|
||||||
|
i.PutExtra(Strings.ExtraActionData, _bundleExtra);
|
||||||
|
i.PutExtra(Strings.ExtraFieldId, _fieldId);
|
||||||
|
i.PutExtra(Strings.ExtraSender, _ctx.PackageName);
|
||||||
|
PluginHost.AddEntryToIntent(i, Entry);
|
||||||
|
|
||||||
|
_ctx.SendBroadcast(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using Android.App;
|
||||||
|
using Android.Views;
|
||||||
|
using Android.Widget;
|
||||||
|
|
||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
internal class StandardStringView : IStringView
|
||||||
|
{
|
||||||
|
private readonly int _viewId;
|
||||||
|
private readonly int _containerViewId;
|
||||||
|
private readonly Activity _activity;
|
||||||
|
|
||||||
|
public StandardStringView(int viewId, int containerViewId, Activity activity)
|
||||||
|
{
|
||||||
|
_viewId = viewId;
|
||||||
|
_containerViewId = containerViewId;
|
||||||
|
_activity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
View container = _activity.FindViewById(_containerViewId);
|
||||||
|
TextView tv = (TextView) _activity.FindViewById(_viewId);
|
||||||
|
if (String.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
container.Visibility = tv.Visibility = ViewStates.Gone;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
container.Visibility = tv.Visibility = ViewStates.Visible;
|
||||||
|
tv.Text = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
TextView tv = (TextView) _activity.FindViewById(_viewId);
|
||||||
|
return tv.Text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
using Android.Graphics.Drawables;
|
||||||
|
using PluginHostTest;
|
||||||
|
|
||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
internal class WriteBinaryToFilePopupItem : IPopupMenuItem
|
||||||
|
{
|
||||||
|
private readonly string _key;
|
||||||
|
private readonly EntryActivity _activity;
|
||||||
|
|
||||||
|
public WriteBinaryToFilePopupItem(string key, EntryActivity activity)
|
||||||
|
{
|
||||||
|
_key = key;
|
||||||
|
_activity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable Icon
|
||||||
|
{
|
||||||
|
get { return _activity.Resources.GetDrawable(Android.Resource.Drawable.IcMenuSave); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get { return _activity.Resources.GetString(Resource.String.SaveAttachmentDialog_save); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleClick()
|
||||||
|
{
|
||||||
|
_activity.WriteBinaryToFile(_key, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,6 @@
|
|||||||
|
using Android.Content.PM;
|
||||||
|
using Android.Content.Res;
|
||||||
|
using Android.Graphics.Drawables;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Android.Views;
|
using Android.Views;
|
||||||
@ -11,26 +14,32 @@ namespace keepass2android
|
|||||||
public class PluginItem
|
public class PluginItem
|
||||||
{
|
{
|
||||||
private readonly string _package;
|
private readonly string _package;
|
||||||
|
private readonly Context _ctx;
|
||||||
|
private readonly Resources _pluginRes;
|
||||||
|
|
||||||
public PluginItem(string package, string _label, int _icon, string _version, string _enabledStatus)
|
public PluginItem(string package, string enabledStatus, Context ctx)
|
||||||
{
|
{
|
||||||
_package = package;
|
_package = package;
|
||||||
Label = _label;
|
_ctx = ctx;
|
||||||
Icon = _icon;
|
EnabledStatus = enabledStatus;
|
||||||
Version = _version;
|
_pluginRes = _ctx.PackageManager.GetResourcesForApplication(_package);
|
||||||
EnabledStatus = _enabledStatus;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Label
|
public string Label
|
||||||
{
|
{
|
||||||
get;
|
get
|
||||||
set;
|
{
|
||||||
|
return PluginDetailsActivity.GetStringFromPlugin(_pluginRes, _package, "kp2aplugin_title");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Version
|
public string Version
|
||||||
{
|
{
|
||||||
get;
|
get
|
||||||
set;
|
{
|
||||||
|
return _ctx.PackageManager.GetPackageInfo(_package, 0).VersionName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string EnabledStatus
|
public string EnabledStatus
|
||||||
@ -39,10 +48,12 @@ namespace keepass2android
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Icon
|
public Drawable Icon
|
||||||
{
|
{
|
||||||
get;
|
get
|
||||||
set;
|
{
|
||||||
|
return _ctx.PackageManager.GetApplicationIcon(_package);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Package
|
public string Package
|
||||||
@ -104,7 +115,7 @@ namespace keepass2android
|
|||||||
holder.txtTitle.Text = item.Label;
|
holder.txtTitle.Text = item.Label;
|
||||||
holder.txtVersion.Text = item.Version;
|
holder.txtVersion.Text = item.Version;
|
||||||
holder.txtEnabledStatus.Text = item.EnabledStatus;
|
holder.txtEnabledStatus.Text = item.EnabledStatus;
|
||||||
holder.imgIcon.SetImageResource(item.Icon);
|
holder.imgIcon.SetImageDrawable(item.Icon);
|
||||||
|
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,18 @@ namespace keepass2android
|
|||||||
|
|
||||||
public bool IsValidAccessToken(string pluginPackage, string accessToken, string scope)
|
public bool IsValidAccessToken(string pluginPackage, string accessToken, string scope)
|
||||||
{
|
{
|
||||||
|
if (pluginPackage == null)
|
||||||
|
{
|
||||||
|
Log.Warn(_tag, "No pluginPackage specified!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessToken == null)
|
||||||
|
{
|
||||||
|
Log.Warn(_tag, "No accessToken specified!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var prefs = GetPreferencesForPlugin(pluginPackage);
|
var prefs = GetPreferencesForPlugin(pluginPackage);
|
||||||
if (prefs.GetString(_accessToken, null) != accessToken)
|
if (prefs.GetString(_accessToken, null) != accessToken)
|
||||||
{
|
{
|
||||||
|
@ -96,7 +96,7 @@ namespace PluginHostTest
|
|||||||
FindViewById<TextView>(resourceId).Visibility = ViewStates.Gone;
|
FindViewById<TextView>(resourceId).Visibility = ViewStates.Gone;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetStringFromPlugin(Resources pluginRes, string pluginPackage, string stringId)
|
public static string GetStringFromPlugin(Resources pluginRes, string pluginPackage, string stringId)
|
||||||
{
|
{
|
||||||
int titleId = pluginRes.GetIdentifier(pluginPackage + ":string/"+stringId, null, null);
|
int titleId = pluginRes.GetIdentifier(pluginPackage + ":string/"+stringId, null, null);
|
||||||
string title = null;
|
string title = null;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Xml.Linq;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Android.Content.PM;
|
using Android.Content.PM;
|
||||||
@ -11,9 +12,12 @@ using Android.Runtime;
|
|||||||
using Android.Util;
|
using Android.Util;
|
||||||
using Android.Views;
|
using Android.Views;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
|
using KeePassLib;
|
||||||
|
using KeePassLib.Serialization;
|
||||||
|
using KeePassLib.Utility;
|
||||||
using Keepass2android;
|
using Keepass2android;
|
||||||
using Keepass2android.Pluginsdk;
|
using Keepass2android.Pluginsdk;
|
||||||
|
using Org.Json;
|
||||||
using PluginHostTest;
|
using PluginHostTest;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
@ -26,7 +30,7 @@ namespace keepass2android
|
|||||||
private const string _tag = "KP2A_PluginHost";
|
private const string _tag = "KP2A_PluginHost";
|
||||||
|
|
||||||
|
|
||||||
private static readonly string[] _validScopes = { Strings.ScopeDatabaseActions };
|
private static readonly string[] _validScopes = { Strings.ScopeDatabaseActions, Strings.ScopeCurrentEntry };
|
||||||
|
|
||||||
public static void TriggerRequests(Context ctx)
|
public static void TriggerRequests(Context ctx)
|
||||||
{
|
{
|
||||||
@ -138,6 +142,34 @@ namespace keepass2android
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void AddEntryToIntent(Intent intent, PwEntry entry)
|
||||||
|
{
|
||||||
|
/*//add the entry XML
|
||||||
|
not yet implemented. What to do with attachments?
|
||||||
|
MemoryStream memStream = new MemoryStream();
|
||||||
|
KdbxFile.WriteEntries(memStream, new[] {entry});
|
||||||
|
string entryData = StrUtil.Utf8.GetString(memStream.ToArray());
|
||||||
|
intent.PutExtra(Strings.ExtraEntryData, entryData);
|
||||||
|
*/
|
||||||
|
//add the compiled string array (placeholders replaced taking into account the db context)
|
||||||
|
Dictionary<string, string> compiledFields = new Dictionary<string, string>();
|
||||||
|
foreach (var pair in entry.Strings)
|
||||||
|
{
|
||||||
|
String key = pair.Key;
|
||||||
|
|
||||||
|
String value = entry.Strings.ReadSafe(key);
|
||||||
|
value = SprEngine.Compile(value, new SprContext(entry, App.Kp2A.GetDb().KpDatabase, SprCompileFlags.All));
|
||||||
|
|
||||||
|
compiledFields.Add(StrUtil.SafeXmlString(pair.Key), value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject json = new JSONObject(compiledFields);
|
||||||
|
var jsonStr = json.ToString();
|
||||||
|
intent.PutExtra(Strings.ExtraCompiledEntryData, jsonStr);
|
||||||
|
|
||||||
|
intent.PutExtra(Strings.ExtraEntryId, entry.Uuid.ToHexString());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -56,24 +56,38 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Activity1.cs" />
|
<Compile Include="Activity1.cs" />
|
||||||
|
<Compile Include="App.cs" />
|
||||||
<Compile Include="ClickView.cs" />
|
<Compile Include="ClickView.cs" />
|
||||||
|
<Compile Include="CopyToClipboardService.cs" />
|
||||||
<Compile Include="EntryActivity.cs" />
|
<Compile Include="EntryActivity.cs" />
|
||||||
<Compile Include="EntryContentsView.cs" />
|
<Compile Include="EntryContentsView.cs" />
|
||||||
<Compile Include="EntrySection.cs" />
|
<Compile Include="EntrySection.cs" />
|
||||||
|
<Compile Include="EntryActivityClasses\ExtraStringView.cs" />
|
||||||
|
<Compile Include="EntryActivityClasses\IPopupMenuItem.cs" />
|
||||||
|
<Compile Include="EntryActivityClasses\IStringView.cs" />
|
||||||
<Compile Include="Kp2aShortHelpView.cs" />
|
<Compile Include="Kp2aShortHelpView.cs" />
|
||||||
|
<Compile Include="EntryActivityClasses\OpenBinaryPopupItem.cs" />
|
||||||
<Compile Include="PluginDatabase.cs" />
|
<Compile Include="PluginDatabase.cs" />
|
||||||
<Compile Include="PluginDetailsActivity.cs" />
|
<Compile Include="PluginDetailsActivity.cs" />
|
||||||
<Compile Include="PluginArrayAdapter.cs" />
|
<Compile Include="PluginArrayAdapter.cs" />
|
||||||
<Compile Include="PluginListActivity.cs" />
|
<Compile Include="PluginListActivity.cs" />
|
||||||
<Compile Include="PluginHost.cs" />
|
<Compile Include="PluginHost.cs" />
|
||||||
|
<Compile Include="EntryActivityClasses\PluginMenuOption.cs" />
|
||||||
|
<Compile Include="EntryActivityClasses\PluginPopupMenuItem.cs" />
|
||||||
<Compile Include="Resources\Resource.Designer.cs" />
|
<Compile Include="Resources\Resource.Designer.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="SprCompileFlags.cs" />
|
||||||
|
<Compile Include="SprContext.cs" />
|
||||||
|
<Compile Include="SprEngine.cs" />
|
||||||
|
<Compile Include="EntryActivityClasses\StandardStringView.cs" />
|
||||||
|
<Compile Include="TextDrawable.cs" />
|
||||||
<Compile Include="TextViewSelect.cs" />
|
<Compile Include="TextViewSelect.cs" />
|
||||||
<Compile Include="TextWithHelp.cs" />
|
<Compile Include="TextWithHelp.cs" />
|
||||||
|
<Compile Include="EntryActivityClasses\WriteBinaryToFilePopupItem.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<TransformFile Include="Assets\DejaVuSansMono.ttf" />
|
<AndroidAsset Include="Assets\DejaVuSansMono.ttf" />
|
||||||
<TransformFile Include="Assets\fontawesome-webfont.ttf" />
|
<AndroidAsset Include="Assets\fontawesome-webfont.ttf" />
|
||||||
<None Include="Resources\AboutResources.txt" />
|
<None Include="Resources\AboutResources.txt" />
|
||||||
<None Include="Assets\AboutAssets.txt" />
|
<None Include="Assets\AboutAssets.txt" />
|
||||||
<AndroidResource Include="Resources\Layout\plugin_list.xml">
|
<AndroidResource Include="Resources\Layout\plugin_list.xml">
|
||||||
@ -93,6 +107,10 @@
|
|||||||
<TransformFile Include="Properties\AndroidManifest.xml" />
|
<TransformFile Include="Properties\AndroidManifest.xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\KeePassLib2Android\KeePassLib2Android.csproj">
|
||||||
|
<Project>{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}</Project>
|
||||||
|
<Name>KeePassLib2Android</Name>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\PluginSdkBinding\PluginSdkBinding.csproj">
|
<ProjectReference Include="..\PluginSdkBinding\PluginSdkBinding.csproj">
|
||||||
<Project>{3da3911e-36de-465e-8f15-f1991b6437e5}</Project>
|
<Project>{3da3911e-36de-465e-8f15-f1991b6437e5}</Project>
|
||||||
<Name>PluginSdkBinding</Name>
|
<Name>PluginSdkBinding</Name>
|
||||||
@ -567,6 +585,18 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidResource Include="Resources\Layout\entry_view.xml" />
|
<AndroidResource Include="Resources\Layout\entry_view.xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\Drawable\vdots_holodark.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\Drawable\vdots.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\Drawable\ic_menu_copy_holo_light.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\Menu\entry.xml" />
|
||||||
|
</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.
|
||||||
|
@ -14,6 +14,7 @@ namespace keepass2android
|
|||||||
public class PluginListActivity : ListActivity
|
public class PluginListActivity : ListActivity
|
||||||
{
|
{
|
||||||
private PluginArrayAdapter _pluginArrayAdapter;
|
private PluginArrayAdapter _pluginArrayAdapter;
|
||||||
|
private List<PluginItem> _items;
|
||||||
|
|
||||||
protected override void OnCreate(Bundle bundle)
|
protected override void OnCreate(Bundle bundle)
|
||||||
{
|
{
|
||||||
@ -22,31 +23,35 @@ namespace keepass2android
|
|||||||
//TODO _design.ApplyTheme();
|
//TODO _design.ApplyTheme();
|
||||||
|
|
||||||
SetContentView(Resource.Layout.plugin_list);
|
SetContentView(Resource.Layout.plugin_list);
|
||||||
|
|
||||||
|
ListView listView = FindViewById<ListView>(Android.Resource.Id.List);
|
||||||
|
listView.ItemClick +=
|
||||||
|
(sender, args) =>
|
||||||
|
{
|
||||||
|
Intent i = new Intent(this, typeof(PluginDetailsActivity));
|
||||||
|
i.PutExtra("PluginPackage", _items[args.Position].Package);
|
||||||
|
StartActivity(i);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create your application here
|
||||||
|
}
|
||||||
|
protected override void OnResume()
|
||||||
|
{
|
||||||
|
base.OnResume();
|
||||||
PluginDatabase pluginDb = new PluginDatabase(this);
|
PluginDatabase pluginDb = new PluginDatabase(this);
|
||||||
|
|
||||||
List<PluginItem> items = (from pluginPackage in pluginDb.GetAllPluginPackages()
|
_items = (from pluginPackage in pluginDb.GetAllPluginPackages()
|
||||||
let version = PackageManager.GetPackageInfo(pluginPackage, 0).VersionName
|
let version = PackageManager.GetPackageInfo(pluginPackage, 0).VersionName
|
||||||
let enabledStatus = pluginDb.IsEnabled(pluginPackage) ? GetString(Resource.String.plugin_enabled) : GetString(Resource.String.plugin_disabled)
|
let enabledStatus = pluginDb.IsEnabled(pluginPackage) ? GetString(Resource.String.plugin_enabled) : GetString(Resource.String.plugin_disabled)
|
||||||
select new PluginItem(pluginPackage, "the plugin", Resource.Drawable.Icon, version, enabledStatus)).ToList();
|
select new PluginItem(pluginPackage, enabledStatus, this)).ToList();
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
new PluginItem("PluginA", Resource.Drawable.Icon, "keepass2android.plugina", "connected"),
|
new PluginItem("PluginA", Resource.Drawable.Icon, "keepass2android.plugina", "connected"),
|
||||||
new PluginItem("KeepassNFC", Resource.Drawable.Icon, "com.bla.blubb.plugina", "disconnected")
|
new PluginItem("KeepassNFC", Resource.Drawable.Icon, "com.bla.blubb.plugina", "disconnected")
|
||||||
};
|
};
|
||||||
* */
|
* */
|
||||||
_pluginArrayAdapter = new PluginArrayAdapter(this, Resource.Layout.ListViewPluginRow, items);
|
_pluginArrayAdapter = new PluginArrayAdapter(this, Resource.Layout.ListViewPluginRow, _items);
|
||||||
ListAdapter = _pluginArrayAdapter;
|
ListAdapter = _pluginArrayAdapter;
|
||||||
|
|
||||||
ListView listView = FindViewById<ListView>(Android.Resource.Id.List);
|
|
||||||
listView.ItemClick +=
|
|
||||||
(sender, args) =>
|
|
||||||
{
|
|
||||||
Intent i = new Intent(this, typeof(PluginDetailsActivity));
|
|
||||||
i.PutExtra("PluginPackage", items[args.Position].Package);
|
|
||||||
StartActivity(i);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create your application here
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Binary file not shown.
After Width: | Height: | Size: 199 B |
BIN
src/PluginHostTest/Resources/Drawable/vdots.png
Normal file
BIN
src/PluginHostTest/Resources/Drawable/vdots.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 319 B |
BIN
src/PluginHostTest/Resources/Drawable/vdots_holodark.png
Normal file
BIN
src/PluginHostTest/Resources/Drawable/vdots_holodark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 309 B |
@ -1,7 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/extra_title_container"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="fill_parent"
|
||||||
android:text="Title"
|
android:layout_height="wrap_content">
|
||||||
android:layout_marginLeft="10dp"
|
<TextView
|
||||||
style="@style/ExtraFieldHeader" />
|
android:id="@+id/entry_title"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Title"
|
||||||
|
style="@style/EntryFieldHeader" />
|
||||||
|
</LinearLayout>
|
@ -1,8 +1,26 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout
|
||||||
android:layout_width="fill_parent"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_height="wrap_content"
|
android:id="@+id/extra_container"
|
||||||
android:typeface="monospace"
|
android:layout_height="wrap_content"
|
||||||
android:text="Value"
|
android:layout_width="fill_parent"
|
||||||
android:layout_marginLeft="30dp"
|
android:orientation="horizontal"
|
||||||
style="@style/EntryItem" />
|
android:clickable="true"
|
||||||
|
android:background="?android:attr/selectableItemBackground">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/extra_vdots"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="15dp"
|
||||||
|
android:src="@drawable/vdots"
|
||||||
|
android:gravity="right|bottom"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_extra"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:typeface="monospace"
|
||||||
|
android:layout_toLeftOf="@id/extra_vdots"
|
||||||
|
style="@style/EntryItem" />
|
||||||
|
</RelativeLayout>
|
@ -5,162 +5,260 @@
|
|||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<!-- Username -->
|
|
||||||
<TextView
|
<LinearLayout android:id="@+id/entryfield_container_username"
|
||||||
android:id="@+id/entry_user_name_label"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:orientation="vertical">
|
||||||
android:text="@string/entry_user_name"
|
|
||||||
style="@style/EntryFieldHeader"
|
<TextView
|
||||||
|
android:id="@+id/entry_user_name_label"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/entry_user_name"
|
||||||
|
|
||||||
|
style="@style/EntryFieldHeader"
|
||||||
/>
|
/>
|
||||||
<TextView
|
|
||||||
android:id="@+id/entry_user_name"
|
<!-- Username -->
|
||||||
android:layout_width="fill_parent"
|
<RelativeLayout android:id="@+id/username_container"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textIsSelectable="true"
|
android:layout_width="fill_parent"
|
||||||
style="@style/EntryItem" />
|
android:orientation="horizontal"
|
||||||
<!-- URL -->
|
android:clickable="true"
|
||||||
<TextView
|
android:background="?android:attr/selectableItemBackground">
|
||||||
android:id="@+id/entry_url_label"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/entry_url"
|
|
||||||
style="@style/EntryFieldHeader"
|
|
||||||
/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/entry_url"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:autoLink="all"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
style="@style/EntryItem" />
|
|
||||||
<!-- Password -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/entry_password_label"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/entry_password"
|
|
||||||
style="@style/EntryFieldHeader"
|
|
||||||
/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/entry_password"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:password="true"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
android:typeface="monospace"
|
|
||||||
style="@style/EntryItem" />
|
|
||||||
<!-- Comment -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/entry_comment_label"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/entry_comment"
|
|
||||||
style="@style/EntryFieldHeader"
|
|
||||||
/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/entry_comment"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
style="@style/EntryItem" />
|
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<ImageView
|
||||||
android:id="@+id/entry_extra_strings_label"
|
android:id="@+id/username_vdots"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="15dp"
|
||||||
android:text="@string/entry_extra_strings"
|
android:src="@drawable/vdots"
|
||||||
style="@style/EntryFieldHeader"
|
android:gravity="right|bottom"
|
||||||
/>
|
android:layout_alignParentRight="true"
|
||||||
<LinearLayout
|
android:layout_alignParentBottom="true"
|
||||||
android:id="@+id/extra_strings"
|
/>
|
||||||
android:layout_width="fill_parent"
|
<TextView
|
||||||
android:layout_height="wrap_content"
|
android:id="@+id/entry_user_name"
|
||||||
android:layout_marginLeft="12dp"
|
android:layout_width="fill_parent"
|
||||||
android:layout_marginRight="12dp"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical" />
|
android:layout_toLeftOf="@id/username_vdots"
|
||||||
<!-- file attachments -->
|
style="@style/EntryItem" />
|
||||||
<TextView
|
</RelativeLayout>
|
||||||
android:id="@+id/entry_binaries_label"
|
</LinearLayout>
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/entry_binaries"
|
|
||||||
style="@style/EntryFieldHeader"
|
|
||||||
/>
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/binaries"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical" />
|
|
||||||
<!--Tags -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/entry_tags_label"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/entry_tags"
|
|
||||||
style="@style/EntryFieldHeader"
|
|
||||||
/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/entry_tags"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
style="@style/EntryItem" />
|
|
||||||
<!--Override URL-->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/entry_override_url_label"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/entry_override_url"
|
|
||||||
style="@style/EntryFieldHeader"
|
|
||||||
/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/entry_override_url"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:autoLink="all"
|
|
||||||
android:textIsSelectable="true"
|
|
||||||
style="@style/EntryItem" />
|
|
||||||
|
|
||||||
<!-- Created -->
|
<LinearLayout android:id="@+id/entryfield_container_url"
|
||||||
<TextView
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/entry_created_label"
|
android:layout_width="fill_parent"
|
||||||
android:layout_width="fill_parent"
|
android:orientation="vertical">
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/entry_created"
|
<!-- URL -->
|
||||||
style="@style/EntryFieldHeader"
|
<TextView
|
||||||
|
android:id="@+id/entry_url_label"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/entry_url"
|
||||||
|
style="@style/EntryFieldHeader"
|
||||||
|
/>
|
||||||
|
<RelativeLayout android:id="@+id/url_container"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:clickable="true"
|
||||||
|
android:background="?android:attr/selectableItemBackground">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/url_vdots"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="15dp"
|
||||||
|
android:src="@drawable/vdots"
|
||||||
|
android:gravity="right|bottom"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_url"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:autoLink="all"
|
||||||
|
android:layout_toLeftOf="@id/url_vdots"
|
||||||
|
style="@style/EntryItem" />
|
||||||
|
</RelativeLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout android:id="@+id/entryfield_container_password"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- Password -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_password_label"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/entry_password"
|
||||||
|
style="@style/EntryFieldHeader"
|
||||||
/>
|
/>
|
||||||
<TextView
|
<RelativeLayout android:id="@+id/password_container"
|
||||||
android:id="@+id/entry_created"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:orientation="horizontal"
|
||||||
style="@style/EntryItem" />
|
android:clickable="true"
|
||||||
<!-- Modified -->
|
android:background="?android:attr/selectableItemBackground">
|
||||||
<TextView
|
<ImageView
|
||||||
android:id="@+id/entry_modified_label"
|
android:id="@+id/password_vdots"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="15dp"
|
||||||
android:text="@string/entry_modified"
|
android:src="@drawable/vdots"
|
||||||
style="@style/EntryFieldHeader"
|
android:gravity="right|bottom"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_password"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:password="true"
|
||||||
|
android:typeface="monospace"
|
||||||
|
android:layout_toLeftOf="@id/password_vdots"
|
||||||
|
style="@style/EntryItem" />
|
||||||
|
</RelativeLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout android:id="@+id/entryfield_container_comment"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- Comment -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_comment_label"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/entry_comment"
|
||||||
|
style="@style/EntryFieldHeader"
|
||||||
/>
|
/>
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/entry_modified"
|
android:id="@+id/entry_comment"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
style="@style/EntryItem" />
|
android:textIsSelectable="true"
|
||||||
<!-- Expires -->
|
style="@style/EntryItem" />
|
||||||
<TextView
|
</LinearLayout>
|
||||||
android:id="@+id/entry_expires_label"
|
|
||||||
android:layout_width="fill_parent"
|
<LinearLayout
|
||||||
android:layout_height="wrap_content"
|
android:id="@+id/extra_strings"
|
||||||
android:text="@string/entry_expires"
|
android:layout_width="fill_parent"
|
||||||
style="@style/EntryFieldHeader"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
<!-- file attachments -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_binaries_label"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/entry_binaries"
|
||||||
|
style="@style/EntryFieldHeader"
|
||||||
/>
|
/>
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/entry_expires"
|
android:id="@+id/binaries"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
style="@style/EntryItem" />
|
android:orientation="vertical" />
|
||||||
<!-- Property Change Conflict | id:@+id/entry_url_label -->
|
<!--Tags -->
|
||||||
|
<LinearLayout android:id="@+id/entryfield_container_tags"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_tags_label"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/entry_tags"
|
||||||
|
style="@style/EntryFieldHeader"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_tags"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
style="@style/EntryItem" />
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout android:id="@+id/entryfield_container_overrideurl"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!--Override URL-->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_override_url_label"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/entry_override_url"
|
||||||
|
style="@style/EntryFieldHeader"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_override_url"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:autoLink="all"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
style="@style/EntryItem" />
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout android:id="@+id/entryfield_container_created"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Created -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_created_label"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/entry_created"
|
||||||
|
style="@style/EntryFieldHeader"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_created"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/EntryItem" />
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout android:id="@+id/entryfield_container_modified"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- Modified -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_modified_label"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/entry_modified"
|
||||||
|
style="@style/EntryFieldHeader"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_modified"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/EntryItem" />
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout android:id="@+id/entryfield_container_expires"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- Expires -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_expires_label"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/entry_expires"
|
||||||
|
style="@style/EntryFieldHeader"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entry_expires"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/EntryItem" />
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
54
src/PluginHostTest/Resources/Menu/entry.xml
Normal file
54
src/PluginHostTest/Resources/Menu/entry.xml
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
|
||||||
|
|
||||||
|
Keepass2Android is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Keepass2Android is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:id="@+id/menu_donate"
|
||||||
|
android:icon="@android:drawable/ic_menu_share"
|
||||||
|
android:title="@string/menu_donate"
|
||||||
|
/>
|
||||||
|
<item android:id="@+id/menu_toggle_pass"
|
||||||
|
android:icon="@android:drawable/ic_menu_view"
|
||||||
|
android:title="@string/show_password"
|
||||||
|
/>
|
||||||
|
<item android:id="@+id/menu_goto_url"
|
||||||
|
android:icon="@android:drawable/ic_menu_upload"
|
||||||
|
android:title="@string/menu_url"
|
||||||
|
/>
|
||||||
|
<!--<item android:id="@+id/menu_copy_user"
|
||||||
|
android:icon="@android:drawable/ic_menu_set_as"
|
||||||
|
android:title="@string/menu_copy_user"
|
||||||
|
/>
|
||||||
|
<item android:id="@+id/menu_copy_pass"
|
||||||
|
android:icon="@android:drawable/ic_menu_agenda"
|
||||||
|
android:title="@string/menu_copy_pass"
|
||||||
|
/>-->
|
||||||
|
<item android:id="@+id/menu_lock"
|
||||||
|
android:icon="@android:drawable/ic_lock_lock"
|
||||||
|
android:title="@string/menu_lock"
|
||||||
|
/>
|
||||||
|
<item android:id="@+id/menu_suggest_improvements"
|
||||||
|
android:icon="@android:drawable/ic_menu_directions"
|
||||||
|
android:title="@string/suggest_improvements"
|
||||||
|
/>
|
||||||
|
<item android:id="@+id/menu_rate"
|
||||||
|
android:icon="@android:drawable/star_off"
|
||||||
|
android:title="@string/rate_app"
|
||||||
|
/>
|
||||||
|
<item android:id="@+id/menu_translate"
|
||||||
|
android:title="@string/translate_app"
|
||||||
|
/>
|
||||||
|
</menu>
|
@ -54,7 +54,7 @@
|
|||||||
<item name="android:layout_marginRight">12dip</item>
|
<item name="android:layout_marginRight">12dip</item>
|
||||||
<item name="android:paddingLeft">4dp</item>
|
<item name="android:paddingLeft">4dp</item>
|
||||||
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||||
<item name="android:textSize">18sp</item>
|
<item name="android:textSize">16sp</item>
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<style name="EntryFieldHeader">
|
<style name="EntryFieldHeader">
|
||||||
@ -63,11 +63,11 @@
|
|||||||
<item name="android:layout_marginLeft">12dip</item>
|
<item name="android:layout_marginLeft">12dip</item>
|
||||||
<item name="android:layout_marginRight">12dip</item>
|
<item name="android:layout_marginRight">12dip</item>
|
||||||
<item name="android:layout_marginBottom">3dp</item>
|
<item name="android:layout_marginBottom">3dp</item>
|
||||||
<item name="android:layout_marginTop">8dp</item>
|
<item name="android:layout_marginTop">14dp</item>
|
||||||
<item name="android:paddingLeft">4dp</item>
|
<item name="android:paddingLeft">4dp</item>
|
||||||
<item name="android:textAllCaps">true</item>
|
<item name="android:textAllCaps">true</item>
|
||||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||||
<item name="android:textSize">18sp</item>
|
<item name="android:textSize">16sp</item>
|
||||||
<item name="android:textStyle">bold</item>
|
<item name="android:textStyle">bold</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
@ -8,6 +8,6 @@
|
|||||||
<string name="SCOPE_DATABASE_ACTIONS_explanation">Plugin will be notified when a database is opened, closed or saved.</string>
|
<string name="SCOPE_DATABASE_ACTIONS_explanation">Plugin will be notified when a database is opened, closed or saved.</string>
|
||||||
|
|
||||||
<string name="SCOPE_CURRENT_ENTRY_title">Current entry data</string>
|
<string name="SCOPE_CURRENT_ENTRY_title">Current entry data</string>
|
||||||
<string name="SCOPE_CURRENT_ENTRY_explanation">Plugin will receive all data about the current database entry and will be allowed to offer actions on it.</string>
|
<string name="SCOPE_CURRENT_ENTRY_explanation">Plugin will receive all data about the current database entry and will be allowed to offer actions and modify the display of it.</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
7
src/PluginHostTest/SprCompileFlags.cs
Normal file
7
src/PluginHostTest/SprCompileFlags.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
public enum SprCompileFlags
|
||||||
|
{
|
||||||
|
All
|
||||||
|
}
|
||||||
|
}
|
13
src/PluginHostTest/SprContext.cs
Normal file
13
src/PluginHostTest/SprContext.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using KeePassLib;
|
||||||
|
|
||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
public class SprContext
|
||||||
|
{
|
||||||
|
public SprContext(PwEntry entry, PwDatabase kpDatabase, object all)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
src/PluginHostTest/SprEngine.cs
Normal file
11
src/PluginHostTest/SprEngine.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
public class SprEngine
|
||||||
|
|
||||||
|
{
|
||||||
|
public static string Compile(string value, SprContext sprContext)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
56
src/PluginHostTest/TextDrawable.cs
Normal file
56
src/PluginHostTest/TextDrawable.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.Graphics;
|
||||||
|
using Android.Graphics.Drawables;
|
||||||
|
|
||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Shows text as a drawable.
|
||||||
|
/// </summary>
|
||||||
|
/// Based on http://stackoverflow.com/questions/3972445/how-to-put-text-in-a-drawable
|
||||||
|
public class TextDrawable: Drawable {
|
||||||
|
|
||||||
|
private readonly String _text;
|
||||||
|
private readonly Paint _paint;
|
||||||
|
private static Typeface _iconFont;
|
||||||
|
|
||||||
|
public TextDrawable(String text, Context ctx) {
|
||||||
|
|
||||||
|
_text = text;
|
||||||
|
|
||||||
|
|
||||||
|
if (_iconFont == null)
|
||||||
|
_iconFont = Typeface.CreateFromAsset(ctx.Assets, "fontawesome-webfont.ttf");
|
||||||
|
|
||||||
|
_paint = new Paint {Color = (Color.White), TextSize = 22f, AntiAlias = true};
|
||||||
|
//_paint.SetTypeface(_iconFont);
|
||||||
|
_paint.SetShadowLayer(6f, 0, 0, Color.Black);
|
||||||
|
_paint.SetStyle(Paint.Style.Fill);
|
||||||
|
_paint.TextAlign = Paint.Align.Left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void Draw(Canvas canvas) {
|
||||||
|
canvas.DrawText("x"+_text, 0, 0, _paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void SetAlpha(int alpha) {
|
||||||
|
_paint.Alpha = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void SetColorFilter(ColorFilter cf)
|
||||||
|
{
|
||||||
|
_paint.SetColorFilter(cf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Opacity
|
||||||
|
{
|
||||||
|
get { return -3; /*translucent*/ }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package keepass2android.pluginsdk;
|
package keepass2android.pluginsdk;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
@ -10,10 +12,15 @@ import android.content.Intent;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.SharedPreferences.Editor;
|
import android.content.SharedPreferences.Editor;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.PopupMenu;
|
||||||
|
|
||||||
|
|
||||||
public class AccessManager
|
public class AccessManager
|
||||||
{
|
{
|
||||||
|
private static final String _tag = "Kp2aPluginSDK";
|
||||||
private static final String PREF_KEY_SCOPE = "scope";
|
private static final String PREF_KEY_SCOPE = "scope";
|
||||||
private static final String PREF_KEY_TOKEN = "token";
|
private static final String PREF_KEY_TOKEN = "token";
|
||||||
|
|
||||||
@ -49,19 +56,40 @@ public class AccessManager
|
|||||||
public static void storeAccessToken(Context ctx, String hostPackage, String accessToken, ArrayList<String> scopes)
|
public static void storeAccessToken(Context ctx, String hostPackage, String accessToken, ArrayList<String> scopes)
|
||||||
{
|
{
|
||||||
SharedPreferences prefs = getPrefsForHost(ctx, hostPackage);
|
SharedPreferences prefs = getPrefsForHost(ctx, hostPackage);
|
||||||
|
|
||||||
//
|
|
||||||
if (accessToken.equals(prefs.getString(PREF_KEY_TOKEN, "")))
|
|
||||||
{
|
|
||||||
//token already available
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Editor edit = prefs.edit();
|
Editor edit = prefs.edit();
|
||||||
edit.putString(PREF_KEY_TOKEN, accessToken);
|
edit.putString(PREF_KEY_TOKEN, accessToken);
|
||||||
edit.putString(PREF_KEY_SCOPE, stringArrayToString(scopes));
|
String scopesString = stringArrayToString(scopes);
|
||||||
|
edit.putString(PREF_KEY_SCOPE, scopesString);
|
||||||
edit.commit();
|
edit.commit();
|
||||||
|
Log.d(_tag, "stored access token " + accessToken.substring(0, 4)+"... for "+scopes.size()+" scopes ("+scopesString+").");
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
private static SharedPreferences getPrefsForHost(Context ctx,
|
||||||
@ -72,14 +100,22 @@ public class AccessManager
|
|||||||
|
|
||||||
public static String tryGetAccessToken(Context ctx, String hostPackage, ArrayList<String> scopes) {
|
public static String tryGetAccessToken(Context ctx, String hostPackage, ArrayList<String> scopes) {
|
||||||
|
|
||||||
|
if (TextUtils.isEmpty(hostPackage))
|
||||||
|
{
|
||||||
|
Log.d(_tag, "hostPackage is empty!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
SharedPreferences prefs = getPrefsForHost(ctx, hostPackage);
|
SharedPreferences prefs = getPrefsForHost(ctx, hostPackage);
|
||||||
ArrayList<String> currentScope = stringToStringArray(prefs.getString(PREF_KEY_SCOPE, ""));
|
String scopesString = prefs.getString(PREF_KEY_SCOPE, "");
|
||||||
|
Log.d(_tag, "scopes: "+ scopesString);
|
||||||
|
ArrayList<String> currentScope = stringToStringArray(scopesString);
|
||||||
if (isSubset(scopes, currentScope))
|
if (isSubset(scopes, currentScope))
|
||||||
{
|
{
|
||||||
return prefs.getString(PREF_KEY_TOKEN, null);
|
return prefs.getString(PREF_KEY_TOKEN, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Log.d(_tag, "looks like scope changed. Access token invalid.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,7 +124,10 @@ public class AccessManager
|
|||||||
ArrayList<String> availableScopes) {
|
ArrayList<String> availableScopes) {
|
||||||
for (String r: requiredScopes){
|
for (String r: requiredScopes){
|
||||||
if (availableScopes.indexOf(r)<0)
|
if (availableScopes.indexOf(r)<0)
|
||||||
|
{
|
||||||
|
Log.d(_tag, "Scope "+r+" not available. "+availableScopes.size());
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -106,4 +145,15 @@ public class AccessManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,8 @@ public abstract class PluginAccessBroadcastReceiver extends BroadcastReceiver {
|
|||||||
public void onReceive(Context ctx, Intent intent) {
|
public void onReceive(Context ctx, Intent intent) {
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
android.util.Log.d("KP2A.pluginsdk", "received broadcast with action="+action);
|
android.util.Log.d("KP2A.pluginsdk", "received broadcast with action="+action);
|
||||||
|
if (action == null)
|
||||||
|
return;
|
||||||
if (action.equals(Strings.ACTION_TRIGGER_REQUEST_ACCESS))
|
if (action.equals(Strings.ACTION_TRIGGER_REQUEST_ACCESS))
|
||||||
{
|
{
|
||||||
requestAccess(ctx, intent);
|
requestAccess(ctx, intent);
|
||||||
|
@ -1,19 +1,114 @@
|
|||||||
package keepass2android.pluginsdk;
|
package keepass2android.pluginsdk;
|
||||||
|
|
||||||
public class Strings {
|
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";
|
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";
|
public static final String SCOPE_CURRENT_ENTRY = "keepass2android.SCOPE_CURRENT_ENTRY";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra key to transfer a (json serialized) list of scopes
|
||||||
|
*/
|
||||||
public static final String EXTRA_SCOPES = "keepass2android.EXTRA_SCOPES";
|
public static final String EXTRA_SCOPES = "keepass2android.EXTRA_SCOPES";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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";
|
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";
|
public static final String EXTRA_REQUEST_TOKEN = "keepass2android.EXTRA_REQUEST_TOKEN";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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";
|
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";
|
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";
|
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";
|
public static final String ACTION_REVOKE_ACCESS = "keepass2android.ACTION_REVOKE_ACCESS";
|
||||||
|
|
||||||
public static final String EXTRA_ACCESS_TOKEN = "EXTRA_ACCESS_TOKEN";
|
|
||||||
|
|
||||||
//static final String SCOPE_DATABASE_ACTIONS = "keepass2android.SCOPE_DATABASE_ACTIONS";
|
/**
|
||||||
|
* 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 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, compiled using the database context (i.e. placeholders are replaced already)
|
||||||
|
*/
|
||||||
|
public static final String EXTRA_COMPILED_ENTRY_DATA = "keepass2android.EXTRA_COMPILED_ENTRY_DATA";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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";
|
||||||
|
|
||||||
|
/** 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";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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";
|
||||||
|
|
||||||
|
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_";
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user