mirror of
https://github.com/moparisthebest/keepass2android
synced 2024-11-22 09:12: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
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArtTestApp", "ArtTestApp\ArtTestApp.csproj", "{1FF6C335-A627-43C9-AAA7-CBAC2E74CD18}"
|
||||
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
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
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|Win32.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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
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.Text;
|
||||
using System.Linq;
|
||||
|
||||
using System.Threading;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Text;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Android.Preferences;
|
||||
@ -32,79 +34,412 @@ using Android.Content.PM;
|
||||
using Android.Webkit;
|
||||
using Android.Graphics;
|
||||
using Java.IO;
|
||||
using KeePassLib;
|
||||
using KeePassLib.Security;
|
||||
using Keepass2android.Pluginsdk;
|
||||
using PluginHostTest;
|
||||
using Uri = Android.Net.Uri;
|
||||
|
||||
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 KeyRefreshPos = "refresh_pos";
|
||||
public const String KeyCloseAfterCreate = "close_after_create";
|
||||
|
||||
protected PwEntry Entry = new PwEntry(true, true);
|
||||
|
||||
private static Typeface _passwordFont;
|
||||
|
||||
private bool _showPassword;
|
||||
internal bool _showPassword;
|
||||
private int _pos;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
protected void SetupEditButtons() {
|
||||
View edit = FindViewById(Resource.Id.entry_edit);
|
||||
|
||||
protected void SetupEditButtons()
|
||||
{
|
||||
View edit = FindViewById(Resource.Id.entry_edit);
|
||||
if (true)
|
||||
{
|
||||
edit.Visibility = ViewStates.Visible;
|
||||
edit.Click += (sender, e) =>
|
||||
{
|
||||
|
||||
};
|
||||
{
|
||||
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
|
||||
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
|
||||
|
||||
long usageCount = prefs.GetLong(GetString(Resource.String.UsageCount_key), 0);
|
||||
|
||||
ISharedPreferencesEditor edit = prefs.Edit();
|
||||
edit.PutLong(GetString(Resource.String.UsageCount_key), usageCount+1);
|
||||
edit.PutLong(GetString(Resource.String.UsageCount_key), usageCount + 1);
|
||||
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);
|
||||
SetEntryView();
|
||||
|
||||
FillData(false);
|
||||
|
||||
FillData();
|
||||
|
||||
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()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private String getDateTime(DateTime dt) {
|
||||
return dt.ToString ("g", CultureInfo.CurrentUICulture);
|
||||
private String getDateTime(DateTime dt)
|
||||
{
|
||||
return dt.ToString("g", CultureInfo.CurrentUICulture);
|
||||
}
|
||||
|
||||
String concatTags(List<string> tags)
|
||||
private String concatTags(List<string> tags)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (string tag in tags)
|
||||
@ -113,70 +448,98 @@ namespace keepass2android
|
||||
sb.Append(", ");
|
||||
}
|
||||
if (tags.Count > 0)
|
||||
sb.Remove(sb.Length-2,2);
|
||||
sb.Remove(sb.Length - 2, 2);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
void PopulateExtraStrings(bool trimList)
|
||||
private void PopulateExtraStrings()
|
||||
{
|
||||
ViewGroup extraGroup = (ViewGroup)FindViewById(Resource.Id.extra_strings);
|
||||
if (trimList)
|
||||
ViewGroup extraGroup = (ViewGroup) FindViewById(Resource.Id.extra_strings);
|
||||
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.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
|
||||
layoutParams.SetMargins(10,0,0,0);
|
||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FillParent,
|
||||
ViewGroup.LayoutParams.WrapContent);
|
||||
|
||||
layout.LayoutParameters = layoutParams;
|
||||
View viewInflated = LayoutInflater.Inflate(Resource.Layout.entry_extrastring_title,null);
|
||||
TextView keyView = (TextView)viewInflated;
|
||||
View viewInflated = LayoutInflater.Inflate(Resource.Layout.entry_extrastring_title, null);
|
||||
TextView keyView = viewInflated.FindViewById<TextView>(Resource.Id.entry_title);
|
||||
if (key != null)
|
||||
keyView.Text = key;
|
||||
|
||||
layout.AddView(keyView);
|
||||
TextView valueView = (TextView)LayoutInflater.Inflate(Resource.Layout.entry_extrastring_value, null);
|
||||
|
||||
layout.AddView(viewInflated);
|
||||
RelativeLayout valueViewContainer =
|
||||
(RelativeLayout) LayoutInflater.Inflate(Resource.Layout.entry_extrastring_value, null);
|
||||
var valueView = valueViewContainer.FindViewById<TextView>(Resource.Id.entry_extra);
|
||||
if (value != null)
|
||||
valueView.Text = value;
|
||||
SetPasswordTypeface(valueView);
|
||||
if (isProtected)
|
||||
{
|
||||
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)
|
||||
{
|
||||
_protectedTextViews.Add(protectedTextView);
|
||||
}
|
||||
|
||||
|
||||
void PopulateBinaries(bool trimList)
|
||||
private void PopulateBinaries()
|
||||
{
|
||||
ViewGroup binariesGroup = (ViewGroup)FindViewById(Resource.Id.binaries);
|
||||
if (trimList)
|
||||
{
|
||||
binariesGroup.RemoveAllViews();
|
||||
}
|
||||
foreach (KeyValuePair<string, string> pair in new Dictionary<string, string>() { {"abc",""}, {"test.png","uia"} })
|
||||
ViewGroup binariesGroup = (ViewGroup) FindViewById(Resource.Id.binaries);
|
||||
foreach (KeyValuePair<string, string> pair in new Dictionary<string, string>() {{"abc", ""}, {"test.png", "uia"}})
|
||||
{
|
||||
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);
|
||||
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
|
||||
binaryButton.Text = key;
|
||||
@ -206,8 +569,8 @@ namespace keepass2android
|
||||
|
||||
};
|
||||
binariesGroup.AddView(binaryButton,layoutParams);
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
FindViewById(Resource.Id.entry_binaries_label).Visibility = true ? ViewStates.Visible : ViewStates.Gone;
|
||||
}
|
||||
@ -217,7 +580,8 @@ namespace keepass2android
|
||||
{
|
||||
String type = null;
|
||||
String extension = MimeTypeMap.GetFileExtensionFromUrl(url);
|
||||
if (extension != null) {
|
||||
if (extension != null)
|
||||
{
|
||||
MimeTypeMap mime = MimeTypeMap.Singleton;
|
||||
type = mime.GetMimeTypeFromExtension(extension);
|
||||
}
|
||||
@ -229,94 +593,182 @@ namespace keepass2android
|
||||
base.OnBackPressed();
|
||||
}
|
||||
|
||||
protected void FillData(bool trimList)
|
||||
protected void FillData()
|
||||
{
|
||||
_protectedTextViews = new List<TextView>();
|
||||
ImageView iv = (ImageView)FindViewById(Resource.Id.entry_icon);
|
||||
ImageView iv = (ImageView) FindViewById(Resource.Id.entry_icon);
|
||||
if (iv != null)
|
||||
{
|
||||
iv.SetImageDrawable(Resources.GetDrawable(Resource.Drawable.ic00));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ActionBar.Title = "Entry title";
|
||||
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");
|
||||
PopulateText(Resource.Id.entry_password, Resource.Id.entry_password_label, "my password");
|
||||
|
||||
|
||||
|
||||
PopulateStandardText(Resource.Id.entry_user_name, Resource.Id.entryfield_container_username, PwDefs.UserNameField);
|
||||
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));
|
||||
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
|
||||
{
|
||||
FindViewById(Resource.Id.entry_expires).Visibility = ViewStates.Gone;
|
||||
FindViewById(Resource.Id.entry_expires_label).Visibility = ViewStates.Gone;
|
||||
PopulateText(Resource.Id.entry_expires, Resource.Id.entryfield_container_expires, null);
|
||||
}
|
||||
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(trimList);
|
||||
PopulateBinaries();
|
||||
|
||||
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 PopulateText(int viewId, int headerViewId,int resId) {
|
||||
View header = FindViewById(headerViewId);
|
||||
TextView tv = (TextView)FindViewById(viewId);
|
||||
private void PopulateText(int viewId, int containerViewId, int resId)
|
||||
{
|
||||
View header = FindViewById(containerViewId);
|
||||
TextView tv = (TextView) FindViewById(viewId);
|
||||
|
||||
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);
|
||||
TextView tv = (TextView)FindViewById(viewId);
|
||||
View container = FindViewById(containerViewId);
|
||||
TextView tv = (TextView) FindViewById(viewId);
|
||||
if (String.IsNullOrEmpty(text))
|
||||
{
|
||||
header.Visibility = tv.Visibility = ViewStates.Gone;
|
||||
container.Visibility = tv.Visibility = ViewStates.Gone;
|
||||
}
|
||||
else
|
||||
{
|
||||
header.Visibility = tv.Visibility = ViewStates.Visible;
|
||||
container.Visibility = tv.Visibility = ViewStates.Visible;
|
||||
tv.Text = text;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void RequiresRefresh ()
|
||||
private void PopulateStandardText(int viewId, int containerViewId, String key)
|
||||
{
|
||||
Intent ret = new Intent ();
|
||||
ret.PutExtra (KeyRefreshPos, _pos);
|
||||
|
||||
PopulateText(viewId, containerViewId, Entry.Strings.ReadSafe(key));
|
||||
_stringViews.Add(key, new StandardStringView(viewId, containerViewId, this));
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void SetPasswordStyle() {
|
||||
|
||||
private void RequiresRefresh()
|
||||
{
|
||||
Intent ret = new Intent();
|
||||
ret.PutExtra(KeyRefreshPos, _pos);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void SetPasswordStyle()
|
||||
{
|
||||
foreach (TextView password in _protectedTextViews)
|
||||
{
|
||||
|
||||
@ -330,12 +782,13 @@ namespace keepass2android
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnResume()
|
||||
{
|
||||
|
||||
|
||||
base.OnResume();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// brings up a dialog asking the user whether he wants to add the given URL to the entry for automatic finding
|
||||
/// </summary>
|
||||
@ -344,24 +797,50 @@ namespace keepass2android
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
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.SetNegativeButton(GetString(Resource.String.no), (dlgSender, dlgEvt) =>
|
||||
{
|
||||
CompleteOnCreate();
|
||||
});
|
||||
{
|
||||
CompleteOnCreate();
|
||||
});
|
||||
|
||||
Dialog dialog = builder.Create();
|
||||
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.Content;
|
||||
using Android.Views;
|
||||
@ -11,26 +14,32 @@ namespace keepass2android
|
||||
public class PluginItem
|
||||
{
|
||||
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;
|
||||
Label = _label;
|
||||
Icon = _icon;
|
||||
Version = _version;
|
||||
EnabledStatus = _enabledStatus;
|
||||
_ctx = ctx;
|
||||
EnabledStatus = enabledStatus;
|
||||
_pluginRes = _ctx.PackageManager.GetResourcesForApplication(_package);
|
||||
}
|
||||
|
||||
public string Label
|
||||
{
|
||||
get;
|
||||
set;
|
||||
get
|
||||
{
|
||||
return PluginDetailsActivity.GetStringFromPlugin(_pluginRes, _package, "kp2aplugin_title");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public string Version
|
||||
{
|
||||
get;
|
||||
set;
|
||||
get
|
||||
{
|
||||
return _ctx.PackageManager.GetPackageInfo(_package, 0).VersionName;
|
||||
}
|
||||
}
|
||||
|
||||
public string EnabledStatus
|
||||
@ -39,10 +48,12 @@ namespace keepass2android
|
||||
set;
|
||||
}
|
||||
|
||||
public int Icon
|
||||
public Drawable Icon
|
||||
{
|
||||
get;
|
||||
set;
|
||||
get
|
||||
{
|
||||
return _ctx.PackageManager.GetApplicationIcon(_package);
|
||||
}
|
||||
}
|
||||
|
||||
public string Package
|
||||
@ -104,7 +115,7 @@ namespace keepass2android
|
||||
holder.txtTitle.Text = item.Label;
|
||||
holder.txtVersion.Text = item.Version;
|
||||
holder.txtEnabledStatus.Text = item.EnabledStatus;
|
||||
holder.imgIcon.SetImageResource(item.Icon);
|
||||
holder.imgIcon.SetImageDrawable(item.Icon);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
@ -125,6 +125,18 @@ namespace keepass2android
|
||||
|
||||
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);
|
||||
if (prefs.GetString(_accessToken, null) != accessToken)
|
||||
{
|
||||
|
@ -96,7 +96,7 @@ namespace PluginHostTest
|
||||
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);
|
||||
string title = null;
|
||||
|
@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using System.Xml.Linq;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Content.PM;
|
||||
@ -11,9 +12,12 @@ using Android.Runtime;
|
||||
using Android.Util;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
|
||||
using KeePassLib;
|
||||
using KeePassLib.Serialization;
|
||||
using KeePassLib.Utility;
|
||||
using Keepass2android;
|
||||
using Keepass2android.Pluginsdk;
|
||||
using Org.Json;
|
||||
using PluginHostTest;
|
||||
|
||||
namespace keepass2android
|
||||
@ -26,7 +30,7 @@ namespace keepass2android
|
||||
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)
|
||||
{
|
||||
@ -138,6 +142,34 @@ namespace keepass2android
|
||||
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>
|
||||
<Compile Include="Activity1.cs" />
|
||||
<Compile Include="App.cs" />
|
||||
<Compile Include="ClickView.cs" />
|
||||
<Compile Include="CopyToClipboardService.cs" />
|
||||
<Compile Include="EntryActivity.cs" />
|
||||
<Compile Include="EntryContentsView.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="EntryActivityClasses\OpenBinaryPopupItem.cs" />
|
||||
<Compile Include="PluginDatabase.cs" />
|
||||
<Compile Include="PluginDetailsActivity.cs" />
|
||||
<Compile Include="PluginArrayAdapter.cs" />
|
||||
<Compile Include="PluginListActivity.cs" />
|
||||
<Compile Include="PluginHost.cs" />
|
||||
<Compile Include="EntryActivityClasses\PluginMenuOption.cs" />
|
||||
<Compile Include="EntryActivityClasses\PluginPopupMenuItem.cs" />
|
||||
<Compile Include="Resources\Resource.Designer.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="TextWithHelp.cs" />
|
||||
<Compile Include="EntryActivityClasses\WriteBinaryToFilePopupItem.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<TransformFile Include="Assets\DejaVuSansMono.ttf" />
|
||||
<TransformFile Include="Assets\fontawesome-webfont.ttf" />
|
||||
<AndroidAsset Include="Assets\DejaVuSansMono.ttf" />
|
||||
<AndroidAsset Include="Assets\fontawesome-webfont.ttf" />
|
||||
<None Include="Resources\AboutResources.txt" />
|
||||
<None Include="Assets\AboutAssets.txt" />
|
||||
<AndroidResource Include="Resources\Layout\plugin_list.xml">
|
||||
@ -93,6 +107,10 @@
|
||||
<TransformFile Include="Properties\AndroidManifest.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\KeePassLib2Android\KeePassLib2Android.csproj">
|
||||
<Project>{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}</Project>
|
||||
<Name>KeePassLib2Android</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\PluginSdkBinding\PluginSdkBinding.csproj">
|
||||
<Project>{3da3911e-36de-465e-8f15-f1991b6437e5}</Project>
|
||||
<Name>PluginSdkBinding</Name>
|
||||
@ -567,6 +585,18 @@
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\Layout\entry_view.xml" />
|
||||
</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" />
|
||||
<!-- 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.
|
||||
|
@ -14,6 +14,7 @@ namespace keepass2android
|
||||
public class PluginListActivity : ListActivity
|
||||
{
|
||||
private PluginArrayAdapter _pluginArrayAdapter;
|
||||
private List<PluginItem> _items;
|
||||
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
{
|
||||
@ -22,31 +23,35 @@ namespace keepass2android
|
||||
//TODO _design.ApplyTheme();
|
||||
|
||||
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);
|
||||
|
||||
List<PluginItem> items = (from pluginPackage in pluginDb.GetAllPluginPackages()
|
||||
let version = PackageManager.GetPackageInfo(pluginPackage, 0).VersionName
|
||||
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();
|
||||
_items = (from pluginPackage in pluginDb.GetAllPluginPackages()
|
||||
let version = PackageManager.GetPackageInfo(pluginPackage, 0).VersionName
|
||||
let enabledStatus = pluginDb.IsEnabled(pluginPackage) ? GetString(Resource.String.plugin_enabled) : GetString(Resource.String.plugin_disabled)
|
||||
select new PluginItem(pluginPackage, enabledStatus, this)).ToList();
|
||||
/*
|
||||
{
|
||||
new PluginItem("PluginA", Resource.Drawable.Icon, "keepass2android.plugina", "connected"),
|
||||
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;
|
||||
|
||||
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"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Title"
|
||||
android:layout_marginLeft="10dp"
|
||||
style="@style/ExtraFieldHeader" />
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/extra_title_container"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
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"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:typeface="monospace"
|
||||
android:text="Value"
|
||||
android:layout_marginLeft="30dp"
|
||||
style="@style/EntryItem" />
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/extra_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/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:orientation="vertical">
|
||||
|
||||
<!-- Username -->
|
||||
<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"
|
||||
|
||||
<LinearLayout android:id="@+id/entryfield_container_username"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<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"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textIsSelectable="true"
|
||||
style="@style/EntryItem" />
|
||||
<!-- URL -->
|
||||
<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"
|
||||
/>
|
||||
<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" />
|
||||
|
||||
<!-- Username -->
|
||||
<RelativeLayout android:id="@+id/username_container"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:orientation="horizontal"
|
||||
android:clickable="true"
|
||||
android:background="?android:attr/selectableItemBackground">
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/entry_extra_strings_label"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/entry_extra_strings"
|
||||
style="@style/EntryFieldHeader"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:id="@+id/extra_strings"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_marginRight="12dp"
|
||||
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"
|
||||
/>
|
||||
<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" />
|
||||
<ImageView
|
||||
android:id="@+id/username_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_user_name"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toLeftOf="@id/username_vdots"
|
||||
style="@style/EntryItem" />
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 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"
|
||||
<LinearLayout android:id="@+id/entryfield_container_url"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- URL -->
|
||||
<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
|
||||
android:id="@+id/entry_created"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/EntryItem" />
|
||||
<!-- 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"
|
||||
<RelativeLayout android:id="@+id/password_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/password_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_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
|
||||
android:id="@+id/entry_modified"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/EntryItem" />
|
||||
<!-- 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_comment"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textIsSelectable="true"
|
||||
style="@style/EntryItem" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/extra_strings"
|
||||
android:layout_width="fill_parent"
|
||||
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
|
||||
android:id="@+id/entry_expires"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/EntryItem" />
|
||||
<!-- Property Change Conflict | id:@+id/entry_url_label -->
|
||||
<LinearLayout
|
||||
android:id="@+id/binaries"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
<!--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>
|
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:paddingLeft">4dp</item>
|
||||
<item name="android:textColor">?android:attr/textColorSecondary</item>
|
||||
<item name="android:textSize">18sp</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
|
||||
</style>
|
||||
<style name="EntryFieldHeader">
|
||||
@ -63,11 +63,11 @@
|
||||
<item name="android:layout_marginLeft">12dip</item>
|
||||
<item name="android:layout_marginRight">12dip</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:textAllCaps">true</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>
|
||||
</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_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>
|
||||
|
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;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.json.JSONArray;
|
||||
@ -10,10 +12,15 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.PopupMenu;
|
||||
|
||||
|
||||
public class AccessManager
|
||||
{
|
||||
private static final String _tag = "Kp2aPluginSDK";
|
||||
private static final String PREF_KEY_SCOPE = "scope";
|
||||
private static final String PREF_KEY_TOKEN = "token";
|
||||
|
||||
@ -49,19 +56,40 @@ public class AccessManager
|
||||
public static void storeAccessToken(Context ctx, String hostPackage, String accessToken, ArrayList<String> scopes)
|
||||
{
|
||||
SharedPreferences prefs = getPrefsForHost(ctx, hostPackage);
|
||||
|
||||
//
|
||||
if (accessToken.equals(prefs.getString(PREF_KEY_TOKEN, "")))
|
||||
{
|
||||
//token already available
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Editor edit = prefs.edit();
|
||||
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();
|
||||
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,
|
||||
@ -72,14 +100,22 @@ public class AccessManager
|
||||
|
||||
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);
|
||||
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))
|
||||
{
|
||||
return prefs.getString(PREF_KEY_TOKEN, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(_tag, "looks like scope changed. Access token invalid.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -88,7 +124,10 @@ public class AccessManager
|
||||
ArrayList<String> availableScopes) {
|
||||
for (String r: requiredScopes){
|
||||
if (availableScopes.indexOf(r)<0)
|
||||
{
|
||||
Log.d(_tag, "Scope "+r+" not available. "+availableScopes.size());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -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) {
|
||||
String action = intent.getAction();
|
||||
android.util.Log.d("KP2A.pluginsdk", "received broadcast with action="+action);
|
||||
if (action == null)
|
||||
return;
|
||||
if (action.equals(Strings.ACTION_TRIGGER_REQUEST_ACCESS))
|
||||
{
|
||||
requestAccess(ctx, intent);
|
||||
|
@ -1,19 +1,114 @@
|
||||
package keepass2android.pluginsdk;
|
||||
|
||||
public class Strings {
|
||||
/**
|
||||
* Plugin is notified about actions like open/close/update a database.
|
||||
*/
|
||||
public static final String SCOPE_DATABASE_ACTIONS = "keepass2android.SCOPE_DATABASE_ACTIONS";
|
||||
/**
|
||||
* Plugin is notified when an entry is opened.
|
||||
*/
|
||||
public static final String SCOPE_CURRENT_ENTRY = "keepass2android.SCOPE_CURRENT_ENTRY";
|
||||
|
||||
/**
|
||||
* Extra key to transfer a (json serialized) list of 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";
|
||||
|
||||
/**
|
||||
* Extra key for sending a request token. The request token is passed from
|
||||
* KP2A to the plugin. It's used in the authorization process.
|
||||
*/
|
||||
public static final String EXTRA_REQUEST_TOKEN = "keepass2android.EXTRA_REQUEST_TOKEN";
|
||||
|
||||
/**
|
||||
* Action sent from KP2A to the plugin to indicate that the plugin should request
|
||||
* access (sending it's scopes)
|
||||
*/
|
||||
public static final String ACTION_TRIGGER_REQUEST_ACCESS = "keepass2android.ACTION_TRIGGER_REQUEST_ACCESS";
|
||||
/**
|
||||
* Action sent from the plugin to KP2A including the scopes.
|
||||
*/
|
||||
public static final String ACTION_REQUEST_ACCESS = "keepass2android.ACTION_REQUEST_ACCESS";
|
||||
/**
|
||||
* Action sent from the KP2A to the plugin when the user grants access.
|
||||
* Will contain an access token.
|
||||
*/
|
||||
public static final String ACTION_RECEIVE_ACCESS = "keepass2android.ACTION_RECEIVE_ACCESS";
|
||||
/**
|
||||
* Action sent from KP2A to the plugin to indicate that access is not or no longer valid.
|
||||
*/
|
||||
public static final String ACTION_REVOKE_ACCESS = "keepass2android.ACTION_REVOKE_ACCESS";
|
||||
|
||||
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