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

@@ -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"