PluginSDK: Add Action moved to base class. rename classes for simpler binding
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user