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