PluginSDK: Add Action moved to base class. rename classes for simpler binding

This commit is contained in:
Philipp Crocoll
2014-05-30 20:51:07 +02:00
parent 85fb4ba9f8
commit bc99d6e04f
12 changed files with 236 additions and 148 deletions

View File

@@ -25,6 +25,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArtTestApp", "ArtTestApp\Ar
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginSdkBinding", "PluginSdkBinding\PluginSdkBinding.csproj", "{3DA3911E-36DE-465E-8F15-F1991B6437E5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginTOTP", "PluginTOTP\PluginTOTP.csproj", "{F46F101D-4076-4E0A-9781-105598E2F42A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginHostTest", "PluginHostTest\PluginHostTest.csproj", "{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -284,6 +288,54 @@ Global
{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
{F46F101D-4076-4E0A-9781-105598E2F42A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.Debug|Mixed Platforms.Deploy.0 = Debug|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.Debug|Win32.ActiveCfg = Debug|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.Debug|x64.ActiveCfg = Debug|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.Release|Any CPU.Build.0 = Release|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.Release|Any CPU.Deploy.0 = Release|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.Release|Mixed Platforms.Deploy.0 = Release|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.Release|Win32.ActiveCfg = Release|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.Release|x64.ActiveCfg = Release|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.ReleaseNoNet|Any CPU.Deploy.0 = Release|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.ReleaseNoNet|Mixed Platforms.Deploy.0 = Release|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
{F46F101D-4076-4E0A-9781-105598E2F42A}.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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -16,7 +16,6 @@ namespace keepass2android
private const string _accessToken = "accessToken";
private const string _scopes = "scopes";
private const string _requesttoken = "requestToken";
private const string _pluginlist = "pluginList";
@@ -34,14 +33,7 @@ namespace keepass2android
editor.PutString(_requesttoken, Guid.NewGuid().ToString());
editor.Commit();
}
var hostPrefs = GetHostPrefs();
var plugins = hostPrefs.GetStringSet(_pluginlist, new List<string>());
if (!plugins.Contains(packageName))
{
plugins.Add(packageName);
hostPrefs.Edit().PutStringSet(_pluginlist, plugins).Commit();
}
return prefs;
}
@@ -62,8 +54,7 @@ namespace keepass2android
public IEnumerable<String> GetAllPluginPackages()
{
var hostPrefs = GetHostPrefs();
return hostPrefs.GetStringSet(_pluginlist, new List<string>()).Where(IsPackageInstalled);
return PluginHost.GetAllPlugins(_ctx);
}
public bool IsPackageInstalled(string targetPackage)
@@ -88,16 +79,11 @@ namespace keepass2android
public void StorePlugin(string pluginPackage, string accessToken, IList<string> requestedScopes)
{
ISharedPreferences pluginPrefs = GetPreferencesForPlugin(pluginPackage);
pluginPrefs.Edit()
.PutString(_scopes, AccessManager.StringArrayToString(requestedScopes))
.PutString(_accessToken, accessToken)
.Commit();
}
private ISharedPreferences GetHostPrefs()
{
return _ctx.GetSharedPreferences("plugins", FileCreationMode.Private);
pluginPrefs.Edit()
.PutString(_scopes, AccessManager.StringArrayToString(requestedScopes))
.PutString(_accessToken, accessToken)
.Commit();
}
public void SetEnabled(string pluginPackage, bool enabled)
@@ -114,7 +100,7 @@ namespace keepass2android
i.PutExtra(Strings.ExtraAccessToken, accessToken);
_ctx.SendBroadcast(i);
StorePlugin(pluginPackage, accessToken, GetPluginScopes( pluginPackage));
StorePlugin(pluginPackage, accessToken, GetPluginScopes(pluginPackage));
}
else
{
@@ -139,7 +125,7 @@ namespace keepass2android
{
Log.Warn(_tag, "No accessToken specified!");
return false;
}
}
var prefs = GetPreferencesForPlugin(pluginPackage);
if (prefs.GetString(_accessToken, null) != accessToken)
@@ -166,19 +152,18 @@ namespace keepass2android
{
GetPreferencesForPlugin(plugin).Edit().Clear().Commit();
}
GetHostPrefs().Edit().Clear().Commit();
}
public IEnumerable<string> GetPluginsWithAcceptedScope(string scope)
{
return GetAllPluginPackages().Where(plugin =>
{
var prefs = GetPreferencesForPlugin(plugin);
return (prefs.GetString(_accessToken, null) != null)
&& AccessManager.StringToStringArray(prefs.GetString(_scopes, "")).Contains(scope);
{
var prefs = GetPreferencesForPlugin(plugin);
return (prefs.GetString(_accessToken, null) != null)
&& AccessManager.StringToStringArray(prefs.GetString(_scopes, "")).Contains(scope);
});
});
}
public void ClearPlugin(string plugin)
@@ -186,5 +171,30 @@ namespace keepass2android
var prefs = _ctx.GetSharedPreferences("KP2A.Plugin." + plugin, FileCreationMode.Private);
prefs.Edit().Clear().Commit();
}
/// <summary>
/// Checks if the given pluginPackage has been granted the requiredScope
/// </summary>
public bool HasAcceptedScope(string pluginPackage, string requiredScope)
{
if (pluginPackage == null)
{
Log.Warn(_tag, "No pluginPackage specified!");
return false;
}
var prefs = GetPreferencesForPlugin(pluginPackage);
if (prefs.GetString(_accessToken, null) == null)
{
Log.Info(_tag, "No access token for " + pluginPackage);
return false;
}
if (!AccessManager.StringToStringArray(prefs.GetString(_scopes, "")).Contains(requiredScope))
{
Log.Info(_tag, "Scope " + requiredScope + " not granted for " + pluginPackage);
return false;
}
return true;
}
}
}

View File

@@ -15,14 +15,14 @@ using Android.Views;
using Android.Widget;
using Java.Util;
using Keepass2android.Pluginsdk;
using keepass2android;
using PluginHostTest;
using keepass2android.views;
namespace PluginHostTest
namespace keepass2android
{
[Activity(Label = "TODO Details")]
[IntentFilter(new[] { Strings.ActionEditPluginSettings},
Label = AppNames.AppName,
[Activity(Label = "bla")]
[IntentFilter(new[] { Strings.ActionEditPluginSettings },
Label = "bla",
Categories = new[] { Intent.CategoryDefault })]
public class PluginDetailsActivity : Activity
{
@@ -32,7 +32,7 @@ namespace PluginHostTest
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
_pluginPackageName = Intent.GetStringExtra(Strings.ExtraPluginPackage);
var pluginRes = PackageManager.GetResourcesForApplication(_pluginPackageName);
@@ -40,7 +40,7 @@ namespace PluginHostTest
var author = GetStringFromPlugin(pluginRes, _pluginPackageName, "kp2aplugin_author");
var shortDesc = GetStringFromPlugin(pluginRes, _pluginPackageName, "kp2aplugin_shortdesc");
var version = PackageManager.GetPackageInfo(_pluginPackageName, 0).VersionName;
SetContentView(Resource.Layout.plugin_details);
if (title != null)
FindViewById<TextView>(Resource.Id.txtLabel).Text = title;
@@ -49,13 +49,14 @@ namespace PluginHostTest
SetTextOrHide(Resource.Id.txtShortDesc, shortDesc);
_checkbox = FindViewById<CheckBox>(Resource.Id.cb_enabled);
_checkbox.CheckedChange += delegate {
new PluginDatabase(this).SetEnabled(_pluginPackageName, _checkbox.Checked);
};
_checkbox.CheckedChange += delegate
{
new PluginDatabase(this).SetEnabled(_pluginPackageName, _checkbox.Checked);
};
Drawable d = PackageManager.GetApplicationIcon(_pluginPackageName);
FindViewById<ImageView>(Resource.Id.imgIcon).SetImageDrawable(d);
FindViewById<TextView>(Resource.Id.txtVersion).Text = version;
//cannot be wrong to update the view when we received an update
@@ -72,11 +73,11 @@ namespace PluginHostTest
FindViewById(Resource.Id.deny_button).Visibility = ViewStates.Visible;
FindViewById(Resource.Id.accept_button).Click += delegate(object sender, EventArgs args)
{
new PluginDatabase(this).SetEnabled(_pluginPackageName, true);
SetResult(Result.Ok);
Finish();
};
{
new PluginDatabase(this).SetEnabled(_pluginPackageName, true);
SetResult(Result.Ok);
Finish();
};
FindViewById(Resource.Id.deny_button).Click += delegate(object sender, EventArgs args)
{
@@ -120,10 +121,10 @@ namespace PluginHostTest
string scopeId = scope.Substring("keepass2android.".Length);
TextWithHelp help = new TextWithHelp(this,
GetString(Resources.GetIdentifier(scopeId + "_title", "string", PackageName)),
GetString(Resources.GetIdentifier(scopeId + "_explanation", "string", PackageName)));
GetString(Resources.GetIdentifier(scopeId + "_title", "string", PackageName)),
GetString(Resources.GetIdentifier(scopeId + "_explanation", "string", PackageName)));
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FillParent,
ViewGroup.LayoutParams.WrapContent);
ViewGroup.LayoutParams.WrapContent);
help.LayoutParameters = layoutParams;
scopesContainer.AddView(help);
}
@@ -142,7 +143,7 @@ namespace PluginHostTest
public static string GetStringFromPlugin(Resources pluginRes, string pluginPackage, string stringId)
{
int titleId = pluginRes.GetIdentifier(pluginPackage + ":string/"+stringId, null, null);
int titleId = pluginRes.GetIdentifier(pluginPackage + ":string/" + stringId, null, null);
string title = null;
if (titleId != 0)
title = pluginRes.GetString(titleId);

View File

@@ -14,33 +14,38 @@ namespace keepass2android
/// <summary>
/// Class which manages plugins inside the app
/// </summary>
[BroadcastReceiver()]
[IntentFilter(new[] { Strings.ActionRequestAccess})]
public class PluginHost: BroadcastReceiver
[BroadcastReceiver]
[IntentFilter(new[] { Strings.ActionRequestAccess })]
public class PluginHost : BroadcastReceiver
{
private const string _tag = "KP2A_PluginHost";
private static readonly string[] _validScopes = { Strings.ScopeDatabaseActions, Strings.ScopeCurrentEntry };
private const string _tag = "KP2A_PluginHost";
private static readonly string[] _validScopes = { Strings.ScopeDatabaseActions,
Strings.ScopeCurrentEntry,
Strings.ScopeQueryCredentials,
Strings.ScopeQueryCredentialsForOwnPackage};
public static IEnumerable<string> GetAllPlugins(Context ctx)
{
Intent accessIntent = new Intent(Strings.ActionTriggerRequestAccess);
PackageManager packageManager = ctx.PackageManager;
IList<ResolveInfo> dictPacks = packageManager.QueryBroadcastReceivers(
accessIntent, PackageInfoFlags.Receivers);
return dictPacks.Select(ri => ri.ActivityInfo.ApplicationInfo).Select(appInfo => appInfo.PackageName);
}
/// <summary>
/// Sends a broadcast to all potential plugins prompting them to request access to our app.
/// </summary>
public static void TriggerRequests(Context ctx)
{
Intent accessIntent = new Intent(Strings.ActionTriggerRequestAccess);
PackageManager packageManager = ctx.PackageManager;
IList<ResolveInfo> dictPacks = packageManager.QueryBroadcastReceivers(
accessIntent, PackageInfoFlags.Receivers);
PluginDatabase pluginDatabase = new PluginDatabase(ctx);
foreach (ResolveInfo ri in dictPacks)
{
ApplicationInfo appInfo = ri.ActivityInfo.ApplicationInfo;
String pkgName = appInfo.PackageName;
TriggerRequest(ctx, pkgName, pluginDatabase);
}
foreach (string pkg in GetAllPlugins(ctx))
TriggerRequest(ctx, pkg, pluginDatabase);
}
@@ -69,7 +74,7 @@ namespace keepass2android
var senderPackage = intent.GetStringExtra(Strings.ExtraSender);
var requestToken = intent.GetStringExtra(Strings.ExtraRequestToken);
var requestedScopes = intent.GetStringArrayListExtra(Strings.ExtraScopes);
var requestedScopes = intent.GetStringArrayListExtra(Strings.ExtraScopes);
if (!AreScopesValid(requestedScopes))
{
@@ -82,9 +87,9 @@ namespace keepass2android
return;
}
string currentAccessToken = pluginDb.GetAccessToken(senderPackage);
if ((currentAccessToken != null)
if ((currentAccessToken != null)
&& (AccessManager.IsSubset(requestedScopes,
pluginDb.GetPluginScopes(senderPackage))))
pluginDb.GetPluginScopes(senderPackage))))
{
//permission already there.
var i = new Intent(Strings.ActionReceiveAccess);
@@ -116,10 +121,10 @@ namespace keepass2android
context.SendBroadcast(i);
Log.Warn(_tag, "Access token of plugin " + senderPackage + " not (or no more) valid.");
}
}
if (OnReceivedRequest != null)
OnReceivedRequest(this, new PluginHostEventArgs() { Package = senderPackage});
OnReceivedRequest(this, new PluginHostEventArgs() { Package = senderPackage });
}
}
@@ -152,14 +157,16 @@ namespace keepass2android
//add the output string array (placeholders replaced taking into account the db context)
Dictionary<string, string> outputFields = entry.OutputStrings.ToDictionary(pair => StrUtil.SafeXmlString(pair.Key), pair => pair.Value.ReadString());
//add field values as JSON ({ "key":"value", ... } form)
JSONObject json = new JSONObject(outputFields);
var jsonStr = json.ToString();
intent.PutExtra(Strings.ExtraEntryOutputData, jsonStr);
JSONObject jsonOutput = new JSONObject(outputFields);
var jsonOutputStr = jsonOutput.ToString();
intent.PutExtra(Strings.ExtraEntryOutputData, jsonOutputStr);
//add list of which fields are protected (StringArrayExtra)
string[] protectedFieldsList = entry.OutputStrings.Where(s=>s.Value.IsProtected).Select(s => s.Key).ToArray();
intent.PutExtra(Strings.ExtraProtectedFieldsList, protectedFieldsList);
JSONArray jsonProtectedFields = new JSONArray(
(System.Collections.ICollection)entry.OutputStrings
.Where(pair => pair.Value.IsProtected)
.Select(pair => pair.Key)
.ToArray());
intent.PutExtra(Strings.ExtraProtectedFieldsList, jsonProtectedFields.ToString());
intent.PutExtra(Strings.ExtraEntryId, entry.Uuid.ToHexString());

View File

@@ -10,8 +10,8 @@ using PluginHostTest;
namespace keepass2android
{
//TODO theme?
[Activity (Label = "Plugins (TODO)", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden )]
[Activity(Label = "@string/plugins", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden)]
[IntentFilter(new[] { "keepass2android.PluginListActivity" }, Categories = new[] { Intent.CategoryDefault })]
public class PluginListActivity : ListActivity
{
private PluginArrayAdapter _pluginArrayAdapter;
@@ -20,21 +20,21 @@ namespace keepass2android
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
//TODO _design.ApplyTheme();
SetContentView(Resource.Layout.plugin_list);
PluginHost.TriggerRequests(this);
ListView listView = FindViewById<ListView>(Android.Resource.Id.List);
listView.ItemClick +=
(sender, args) =>
{
Intent i = new Intent(this, typeof(PluginDetailsActivity));
i.PutExtra(Strings.ExtraPluginPackage, _items[args.Position].Package);
StartActivity(i);
};
// Create your application here
{
Intent i = new Intent(this, typeof(PluginDetailsActivity));
i.PutExtra(Strings.ExtraPluginPackage, _items[args.Position].Package);
StartActivity(i);
};
}
protected override void OnResume()
{
@@ -42,9 +42,9 @@ namespace keepass2android
PluginDatabase pluginDb = new PluginDatabase(this);
_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();
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"),

View File

@@ -25,7 +25,7 @@
android:layout_gravity="center"
android:paddingRight="20dp"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:gravity="center_vertical"
android:text="@string/accept" />
</FrameLayout>
<FrameLayout
@@ -40,7 +40,6 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingRight="20dp"
android:drawableLeft="?attr/CancelDrawable"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:text="@string/deny" />
@@ -50,8 +49,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/plugin_scroll"
android:layout_width="wrap_content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:scrollbarStyle="insideOverlay">
<LinearLayout android:id="@+id/scopes_list"
android:layout_width="fill_parent"

View File

@@ -4,14 +4,15 @@
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:orientation="vertical"
android:padding="12dp">
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="plugin text"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="plugin_web"
style="@style/PaddedElement"
android:id="@+id/textView"
android:id="@+id/btnPluginsOnline"
android:layout_gravity="left|center_vertical" />
<ListView
android:id="@android:id/list"

View File

@@ -68,16 +68,42 @@ public abstract class PluginActionBroadcastReceiver extends BroadcastReceiver {
{
return _intent.getStringArrayExtra(Strings.EXTRA_PROTECTED_FIELDS_LIST);
}
public String getEntryId()
{
return _intent.getStringExtra(Strings.EXTRA_ENTRY_ID);
}
public void setEntryField(String fieldId, String fieldValue, boolean isProtected) throws PluginAccessException
{
Intent i = new Intent(Strings.ACTION_SET_ENTRY_FIELD);
ArrayList<String> scope = new ArrayList<String>();
scope.add(Strings.SCOPE_CURRENT_ENTRY);
i.putExtra(Strings.EXTRA_ACCESS_TOKEN, AccessManager.getAccessToken(_context, getHostPackage(), scope));
i.setPackage(getHostPackage());
i.putExtra(Strings.EXTRA_SENDER, _context.getPackageName());
i.putExtra(Strings.EXTRA_FIELD_VALUE, fieldValue);
i.putExtra(Strings.EXTRA_ENTRY_ID, getEntryId());
i.putExtra(Strings.EXTRA_FIELD_ID, fieldId);
i.putExtra(Strings.EXTRA_FIELD_PROTECTED, isProtected);
_context.sendBroadcast(i);
}
}
protected class ActionSelected extends PluginEntryActionBase
protected class ActionSelectedAction extends PluginEntryActionBase
{
public ActionSelected(Context ctx, Intent intent) {
public ActionSelectedAction(Context ctx, Intent intent) {
super(ctx, intent);
}
/**
*
* @return the Bundle associated with the action. This bundle can be set in OpenEntry.add(Entry)FieldAction
@@ -125,9 +151,9 @@ public abstract class PluginActionBroadcastReceiver extends BroadcastReceiver {
}
}
protected class CloseEntryView extends PluginEntryActionBase
protected class CloseEntryViewAction extends PluginEntryActionBase
{
public CloseEntryView(Context context, Intent intent) {
public CloseEntryViewAction(Context context, Intent intent) {
super(context, intent);
}
@@ -137,18 +163,14 @@ public abstract class PluginActionBroadcastReceiver extends BroadcastReceiver {
}
}
protected class OpenEntry extends PluginEntryActionBase
protected class OpenEntryAction extends PluginEntryActionBase
{
public OpenEntry(Context context, Intent intent)
public OpenEntryAction(Context context, Intent intent)
{
super(context, intent);
}
public String getEntryId()
{
return _intent.getStringExtra(Strings.EXTRA_ENTRY_ID);
}
public HashMap<String, String> getEntryFields()
{
@@ -187,21 +209,7 @@ public abstract class PluginActionBroadcastReceiver extends BroadcastReceiver {
_context.sendBroadcast(i);
}
public void setEntryField(String fieldId, String fieldValue, boolean isProtected) throws PluginAccessException
{
Intent i = new Intent(Strings.ACTION_SET_ENTRY_FIELD);
ArrayList<String> scope = new ArrayList<String>();
scope.add(Strings.SCOPE_CURRENT_ENTRY);
i.putExtra(Strings.EXTRA_ACCESS_TOKEN, AccessManager.getAccessToken(_context, getHostPackage(), scope));
i.setPackage(getHostPackage());
i.putExtra(Strings.EXTRA_SENDER, _context.getPackageName());
i.putExtra(Strings.EXTRA_FIELD_VALUE, fieldValue);
i.putExtra(Strings.EXTRA_ENTRY_ID, getEntryId());
i.putExtra(Strings.EXTRA_FIELD_ID, fieldId);
i.putExtra(Strings.EXTRA_FIELD_PROTECTED, isProtected);
_context.sendBroadcast(i);
}
}
@@ -231,10 +239,10 @@ public abstract class PluginActionBroadcastReceiver extends BroadcastReceiver {
}
//EntryOutputModified is very similar to OpenEntry because it receives the same
//data (+ the field id which was modified)
protected class EntryOutputModified extends OpenEntry
protected class EntryOutputModifiedAction extends OpenEntryAction
{
public EntryOutputModified(Context context, Intent intent)
public EntryOutputModifiedAction(Context context, Intent intent)
{
super(context, intent);
}
@@ -253,26 +261,26 @@ public abstract class PluginActionBroadcastReceiver extends BroadcastReceiver {
return;
if (action.equals(Strings.ACTION_OPEN_ENTRY))
{
openEntry(new OpenEntry(ctx, intent));
openEntry(new OpenEntryAction(ctx, intent));
}
else if (action.equals(Strings.ACTION_CLOSE_ENTRY_VIEW))
{
closeEntryView(new CloseEntryView(ctx, intent));
closeEntryView(new CloseEntryViewAction(ctx, intent));
}
else if (action.equals(Strings.ACTION_ENTRY_ACTION_SELECTED))
{
actionSelected(new ActionSelected(ctx, intent));
actionSelected(new ActionSelectedAction(ctx, intent));
}
else if (action.equals(Strings.ACTION_ENTRY_OUTPUT_MODIFIED))
{
entryOutputModified(new EntryOutputModified(ctx, intent));
entryOutputModified(new EntryOutputModifiedAction(ctx, intent));
}
else if (action.equals(Strings.ACTION_LOCK_DATABASE)
|| action.equals(Strings.ACTION_UNLOCK_DATABASE)
|| action.equals(Strings.ACTION_OPEN_DATABASE)
|| action.equals(Strings.ACTION_CLOSE_DATABASE))
{
databaseAction(new DatabaseAction(ctx, intent));
dbAction(new DatabaseAction(ctx, intent));
}
else
{
@@ -282,14 +290,14 @@ public abstract class PluginActionBroadcastReceiver extends BroadcastReceiver {
}
protected void closeEntryView(CloseEntryView closeEntryView) {}
protected void closeEntryView(CloseEntryViewAction closeEntryView) {}
protected void actionSelected(ActionSelected actionSelected) {}
protected void actionSelected(ActionSelectedAction actionSelected) {}
protected void openEntry(OpenEntry oe) {}
protected void openEntry(OpenEntryAction oe) {}
protected void entryOutputModified(EntryOutputModified eom) {}
protected void entryOutputModified(EntryOutputModifiedAction eom) {}
protected void databaseAction(DatabaseAction db) {}
protected void dbAction(DatabaseAction db) {}
}

View File

@@ -10,7 +10,7 @@ import keepass2android.pluginsdk.Strings;
public class ActionReceiver extends PluginActionBroadcastReceiver{
@Override
protected void openEntry(OpenEntry oe) {
protected void openEntry(OpenEntryAction oe) {
try {
oe.addEntryAction(oe.getContext().getString(R.string.action_show_qr),
R.drawable.qrcode, null);
@@ -26,7 +26,7 @@ public class ActionReceiver extends PluginActionBroadcastReceiver{
}
@Override
protected void actionSelected(ActionSelected actionSelected) {
protected void actionSelected(ActionSelectedAction actionSelected) {
Intent i = new Intent(actionSelected.getContext(), QRActivity.class);
i.putExtra(Strings.EXTRA_ENTRY_OUTPUT_DATA, new JSONObject(actionSelected.getEntryFields()).toString());
i.putExtra(Strings.EXTRA_FIELD_ID, actionSelected.getFieldId());
@@ -36,7 +36,7 @@ public class ActionReceiver extends PluginActionBroadcastReceiver{
}
@Override
protected void entryOutputModified(EntryOutputModified eom) {
protected void entryOutputModified(EntryOutputModifiedAction eom) {
try {
eom.addEntryFieldAction("keepass2android.plugin.qr.show", eom.getModifiedFieldId(), eom.getContext().getString(R.string.action_show_qr),
R.drawable.qrcode, null);

View File

@@ -99,6 +99,8 @@ namespace keepass2android
//make sure _timer doesn't go out of scope:
private Timer _timer;
private PluginActionReceiver _pluginActionReceiver;
private PluginFieldReceiver _pluginFieldReceiver;
protected void SetEntryView()
@@ -375,8 +377,10 @@ namespace keepass2android
App.Kp2a.GetDb().LastOpenedEntry = new PwEntryOutput(Entry, App.Kp2a.GetDb().KpDatabase);
RegisterReceiver(new PluginActionReceiver(this), new IntentFilter(Strings.ActionAddEntryAction));
RegisterReceiver(new PluginFieldReceiver(this), new IntentFilter(Strings.ActionSetEntryField));
_pluginActionReceiver = new PluginActionReceiver(this);
RegisterReceiver(_pluginActionReceiver, new IntentFilter(Strings.ActionAddEntryAction));
_pluginFieldReceiver = new PluginFieldReceiver(this);
RegisterReceiver(_pluginFieldReceiver, new IntentFilter(Strings.ActionSetEntryField));
new Thread(NotifyPluginsOnOpen).Start();
@@ -742,6 +746,10 @@ namespace keepass2android
protected override void OnDestroy()
{
NotifyPluginsOnClose();
if (_pluginActionReceiver != null)
UnregisterReceiver(_pluginActionReceiver);
if (_pluginFieldReceiver != null)
UnregisterReceiver(_pluginFieldReceiver);
base.OnDestroy();
}

View File

@@ -56,8 +56,9 @@ namespace keepass2android
Intent triggerIntent = new Intent(Strings.ActionTriggerRequestAccess);
triggerIntent.SetPackage(pkgName);
triggerIntent.PutExtra(Strings.ExtraSender, ctx.PackageName);
triggerIntent.PutExtra(Strings.ExtraRequestToken, pluginDatabase.GetRequestToken(pkgName));
string requestToken = pluginDatabase.GetRequestToken(pkgName);
triggerIntent.PutExtra(Strings.ExtraRequestToken, requestToken);
Android.Util.Log.Debug(_tag, "Request token: " + requestToken);
ctx.SendBroadcast(triggerIntent);
}
catch (Exception e)