From f5628e5581389c6a5078c79fdcf214055e995de6 Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Sat, 15 Dec 2012 01:16:48 +0000
Subject: [PATCH] Use Guice rather than reflection to load plugins.

This allows different plugins to have different dependencies without
cluttering the plugin factory API.
---
 .../plugins/duplex/DuplexPluginConfig.java    |   8 ++
 .../plugins/duplex/DuplexPluginFactory.java   |   9 +-
 .../plugins/simplex/SimplexPluginConfig.java  |   8 ++
 .../plugins/simplex/SimplexPluginFactory.java |   9 +-
 .../sf/briar/plugins/PluginManagerImpl.java   | 133 ++++++------------
 .../net/sf/briar/plugins/PluginsModule.java   |  60 ++++++++
 .../bluetooth/BluetoothPluginFactory.java     |  13 +-
 .../droidtooth/DroidtoothPluginFactory.java   |  16 ++-
 .../file/RemovableDrivePluginFactory.java     |  14 +-
 .../plugins/modem/ModemPluginFactory.java     |  14 +-
 .../plugins/tcp/LanTcpPluginFactory.java      |  13 +-
 .../plugins/tcp/WanTcpPluginFactory.java      |  15 +-
 .../briar/plugins/tor/TorPluginFactory.java   |  14 +-
 .../briar/plugins/PluginManagerImplTest.java  |  41 ++++--
 14 files changed, 209 insertions(+), 158 deletions(-)
 create mode 100644 briar-api/src/net/sf/briar/api/plugins/duplex/DuplexPluginConfig.java
 create mode 100644 briar-api/src/net/sf/briar/api/plugins/simplex/SimplexPluginConfig.java

diff --git a/briar-api/src/net/sf/briar/api/plugins/duplex/DuplexPluginConfig.java b/briar-api/src/net/sf/briar/api/plugins/duplex/DuplexPluginConfig.java
new file mode 100644
index 0000000000..ac064815b9
--- /dev/null
+++ b/briar-api/src/net/sf/briar/api/plugins/duplex/DuplexPluginConfig.java
@@ -0,0 +1,8 @@
+package net.sf.briar.api.plugins.duplex;
+
+import java.util.Collection;
+
+public interface DuplexPluginConfig {
+
+	Collection<DuplexPluginFactory> getFactories();
+}
diff --git a/briar-api/src/net/sf/briar/api/plugins/duplex/DuplexPluginFactory.java b/briar-api/src/net/sf/briar/api/plugins/duplex/DuplexPluginFactory.java
index 9acaa56756..4919f9fc23 100644
--- a/briar-api/src/net/sf/briar/api/plugins/duplex/DuplexPluginFactory.java
+++ b/briar-api/src/net/sf/briar/api/plugins/duplex/DuplexPluginFactory.java
@@ -1,17 +1,10 @@
 package net.sf.briar.api.plugins.duplex;
 
-import java.util.concurrent.Executor;
-
-import net.sf.briar.api.android.AndroidExecutor;
-import net.sf.briar.api.lifecycle.ShutdownManager;
 import net.sf.briar.api.protocol.TransportId;
-import android.content.Context;
 
 public interface DuplexPluginFactory {
 
 	TransportId getId();
 
-	DuplexPlugin createPlugin(Executor pluginExecutor,
-			AndroidExecutor androidExecutor, Context appContext,
-			ShutdownManager shutdownManager, DuplexPluginCallback callback);
+	DuplexPlugin createPlugin(DuplexPluginCallback callback);
 }
diff --git a/briar-api/src/net/sf/briar/api/plugins/simplex/SimplexPluginConfig.java b/briar-api/src/net/sf/briar/api/plugins/simplex/SimplexPluginConfig.java
new file mode 100644
index 0000000000..231d39bc3d
--- /dev/null
+++ b/briar-api/src/net/sf/briar/api/plugins/simplex/SimplexPluginConfig.java
@@ -0,0 +1,8 @@
+package net.sf.briar.api.plugins.simplex;
+
+import java.util.Collection;
+
+public interface SimplexPluginConfig {
+
+	Collection<SimplexPluginFactory> getFactories();
+}
diff --git a/briar-api/src/net/sf/briar/api/plugins/simplex/SimplexPluginFactory.java b/briar-api/src/net/sf/briar/api/plugins/simplex/SimplexPluginFactory.java
index 9970db4e0f..f6a9f2ea86 100644
--- a/briar-api/src/net/sf/briar/api/plugins/simplex/SimplexPluginFactory.java
+++ b/briar-api/src/net/sf/briar/api/plugins/simplex/SimplexPluginFactory.java
@@ -1,17 +1,10 @@
 package net.sf.briar.api.plugins.simplex;
 
-import java.util.concurrent.Executor;
-
-import net.sf.briar.api.android.AndroidExecutor;
-import net.sf.briar.api.lifecycle.ShutdownManager;
 import net.sf.briar.api.protocol.TransportId;
-import android.content.Context;
 
 public interface SimplexPluginFactory {
 
 	TransportId getId();
 
-	SimplexPlugin createPlugin(Executor pluginExecutor,
-			AndroidExecutor androidExecutor, Context appContext,
-			ShutdownManager shutdownManager, SimplexPluginCallback callback);
+	SimplexPlugin createPlugin(SimplexPluginCallback callback);
 }
diff --git a/briar-core/src/net/sf/briar/plugins/PluginManagerImpl.java b/briar-core/src/net/sf/briar/plugins/PluginManagerImpl.java
index a785156fbc..697b84346c 100644
--- a/briar-core/src/net/sf/briar/plugins/PluginManagerImpl.java
+++ b/briar-core/src/net/sf/briar/plugins/PluginManagerImpl.java
@@ -20,24 +20,24 @@ import net.sf.briar.api.TransportProperties;
 import net.sf.briar.api.android.AndroidExecutor;
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DbException;
-import net.sf.briar.api.lifecycle.ShutdownManager;
 import net.sf.briar.api.plugins.Plugin;
 import net.sf.briar.api.plugins.PluginCallback;
 import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.plugins.PluginManager;
 import net.sf.briar.api.plugins.duplex.DuplexPlugin;
 import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
+import net.sf.briar.api.plugins.duplex.DuplexPluginConfig;
 import net.sf.briar.api.plugins.duplex.DuplexPluginFactory;
 import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
 import net.sf.briar.api.plugins.simplex.SimplexPlugin;
 import net.sf.briar.api.plugins.simplex.SimplexPluginCallback;
+import net.sf.briar.api.plugins.simplex.SimplexPluginConfig;
 import net.sf.briar.api.plugins.simplex.SimplexPluginFactory;
 import net.sf.briar.api.plugins.simplex.SimplexTransportReader;
 import net.sf.briar.api.plugins.simplex.SimplexTransportWriter;
 import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.transport.ConnectionDispatcher;
 import net.sf.briar.api.ui.UiCallback;
-import net.sf.briar.util.OsUtils;
 import android.content.Context;
 
 import com.google.inject.Inject;
@@ -47,30 +47,10 @@ class PluginManagerImpl implements PluginManager {
 	private static final Logger LOG =
 			Logger.getLogger(PluginManagerImpl.class.getName());
 
-	private static final String[] ANDROID_SIMPLEX_FACTORIES = new String[0];
-
-	private static final String[] ANDROID_DUPLEX_FACTORIES = new String[] {
-		"net.sf.briar.plugins.droidtooth.DroidtoothPluginFactory",
-		"net.sf.briar.plugins.tcp.LanTcpPluginFactory",
-		"net.sf.briar.plugins.tcp.WanTcpPluginFactory",
-		"net.sf.briar.plugins.tor.TorPluginFactory"
-	};
-
-	private static final String[] J2SE_SIMPLEX_FACTORIES = new String[] {
-		"net.sf.briar.plugins.file.RemovableDrivePluginFactory"
-	};
-
-	private static final String[] J2SE_DUPLEX_FACTORIES = new String[] {
-		"net.sf.briar.plugins.bluetooth.BluetoothPluginFactory",
-		"net.sf.briar.plugins.modem.ModemPluginFactory",
-		"net.sf.briar.plugins.tcp.LanTcpPluginFactory",
-		"net.sf.briar.plugins.tcp.WanTcpPluginFactory",
-		"net.sf.briar.plugins.tor.TorPluginFactory"
-	};
-
 	private final ExecutorService pluginExecutor;
 	private final AndroidExecutor androidExecutor;
-	private final ShutdownManager shutdownManager;
+	private final SimplexPluginConfig simplexPluginConfig;
+	private final DuplexPluginConfig duplexPluginConfig;
 	private final DatabaseComponent db;
 	private final Poller poller;
 	private final ConnectionDispatcher dispatcher;
@@ -80,12 +60,15 @@ class PluginManagerImpl implements PluginManager {
 
 	@Inject
 	PluginManagerImpl(@PluginExecutor ExecutorService pluginExecutor,
-			AndroidExecutor androidExecutor, ShutdownManager shutdownManager,
-			DatabaseComponent db, Poller poller,
-			ConnectionDispatcher dispatcher, UiCallback uiCallback) {
+			AndroidExecutor androidExecutor,
+			SimplexPluginConfig simplexPluginConfig, 
+			DuplexPluginConfig duplexPluginConfig, DatabaseComponent db,
+			Poller poller, ConnectionDispatcher dispatcher,
+			UiCallback uiCallback) {
 		this.pluginExecutor = pluginExecutor;
 		this.androidExecutor = androidExecutor;
-		this.shutdownManager = shutdownManager;
+		this.simplexPluginConfig = simplexPluginConfig;
+		this.duplexPluginConfig = duplexPluginConfig;
 		this.db = db;
 		this.poller = poller;
 		this.dispatcher = dispatcher;
@@ -98,27 +81,23 @@ class PluginManagerImpl implements PluginManager {
 		Set<TransportId> ids = new HashSet<TransportId>();
 		// Instantiate and start the simplex plugins
 		if(LOG.isLoggable(INFO)) LOG.info("Starting simplex plugins");
-		for(String s : getSimplexPluginFactoryNames()) {
-			try {
-				Class<?> c = Class.forName(s);
-				SimplexPluginFactory factory =
-						(SimplexPluginFactory) c.newInstance();
-				TransportId id = factory.getId();
-				if(!ids.add(id)) {
-					if(LOG.isLoggable(WARNING))
-						LOG.warning("Duplicate transport ID: " + id);
-					continue;
-				}
-				SimplexCallback callback = new SimplexCallback(id);
-				SimplexPlugin plugin = factory.createPlugin(pluginExecutor,
-						androidExecutor, appContext, shutdownManager, callback);
-				if(plugin == null) {
-					if(LOG.isLoggable(INFO)) {
-						LOG.info(factory.getClass().getSimpleName()
-								+ " did not create a plugin");
-					}
-					continue;
+		for(SimplexPluginFactory factory : simplexPluginConfig.getFactories()) {
+			TransportId id = factory.getId();
+			if(!ids.add(id)) {
+				if(LOG.isLoggable(WARNING))
+					LOG.warning("Duplicate transport ID: " + id);
+				continue;
+			}
+			SimplexCallback callback = new SimplexCallback(id);
+			SimplexPlugin plugin = factory.createPlugin(callback);
+			if(plugin == null) {
+				if(LOG.isLoggable(INFO)) {
+					LOG.info(factory.getClass().getSimpleName()
+							+ " did not create a plugin");
 				}
+				continue;
+			}
+			try {
 				if(plugin.start()) {
 					simplexPlugins.add(plugin);
 				} else {
@@ -126,37 +105,29 @@ class PluginManagerImpl implements PluginManager {
 						LOG.info(plugin.getClass().getSimpleName()
 								+ " did not start");
 				}
-			} catch(ClassCastException e) {
-				if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
-				continue;
-			} catch(Exception e) {
+			} catch(IOException e) {
 				if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
-				continue;
 			}
 		}
 		// Instantiate and start the duplex plugins
 		if(LOG.isLoggable(INFO)) LOG.info("Starting duplex plugins");
-		for(String s : getDuplexPluginFactoryNames()) {
-			try {
-				Class<?> c = Class.forName(s);
-				DuplexPluginFactory factory =
-						(DuplexPluginFactory) c.newInstance();
-				TransportId id = factory.getId();
-				if(!ids.add(id)) {
-					if(LOG.isLoggable(WARNING))
-						LOG.warning("Duplicate transport ID: " + id);
-					continue;
-				}
-				DuplexCallback callback = new DuplexCallback(id);
-				DuplexPlugin plugin = factory.createPlugin(pluginExecutor,
-						androidExecutor, appContext, shutdownManager, callback);
-				if(plugin == null) {
-					if(LOG.isLoggable(INFO)) {
-						LOG.info(factory.getClass().getSimpleName()
-								+ " did not create a plugin");
-					}
-					continue;
+		for(DuplexPluginFactory factory : duplexPluginConfig.getFactories()) {
+			TransportId id = factory.getId();
+			if(!ids.add(id)) {
+				if(LOG.isLoggable(WARNING))
+					LOG.warning("Duplicate transport ID: " + id);
+				continue;
+			}
+			DuplexCallback callback = new DuplexCallback(id);
+			DuplexPlugin plugin = factory.createPlugin(callback);
+			if(plugin == null) {
+				if(LOG.isLoggable(INFO)) {
+					LOG.info(factory.getClass().getSimpleName()
+							+ " did not create a plugin");
 				}
+				continue;
+			}
+			try {
 				if(plugin.start()) {
 					duplexPlugins.add(plugin);
 				} else {
@@ -164,12 +135,8 @@ class PluginManagerImpl implements PluginManager {
 						LOG.info(plugin.getClass().getSimpleName()
 								+ " did not start");
 				}
-			} catch(ClassCastException e) {
-				if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
-				continue;
-			} catch(Exception e) {
+			} catch(IOException e) {
 				if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
-				continue;
 			}
 		}
 		// Start the poller
@@ -182,16 +149,6 @@ class PluginManagerImpl implements PluginManager {
 		return simplexPlugins.size() + duplexPlugins.size();
 	}
 
-	private static String[] getSimplexPluginFactoryNames() {
-		if(OsUtils.isAndroid()) return ANDROID_SIMPLEX_FACTORIES;
-		return J2SE_SIMPLEX_FACTORIES;
-	}
-
-	private static String[] getDuplexPluginFactoryNames() {
-		if(OsUtils.isAndroid()) return ANDROID_DUPLEX_FACTORIES;
-		return J2SE_DUPLEX_FACTORIES;
-	}
-
 	public synchronized int stop() {
 		int stopped = 0;
 		// Stop the poller
diff --git a/briar-core/src/net/sf/briar/plugins/PluginsModule.java b/briar-core/src/net/sf/briar/plugins/PluginsModule.java
index fa5ff5d42f..5003d1cfc1 100644
--- a/briar-core/src/net/sf/briar/plugins/PluginsModule.java
+++ b/briar-core/src/net/sf/briar/plugins/PluginsModule.java
@@ -1,12 +1,31 @@
 package net.sf.briar.plugins;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
+import net.sf.briar.api.android.AndroidExecutor;
+import net.sf.briar.api.lifecycle.ShutdownManager;
 import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.plugins.PluginManager;
+import net.sf.briar.api.plugins.duplex.DuplexPluginConfig;
+import net.sf.briar.api.plugins.duplex.DuplexPluginFactory;
+import net.sf.briar.api.plugins.simplex.SimplexPluginConfig;
+import net.sf.briar.api.plugins.simplex.SimplexPluginFactory;
+import net.sf.briar.plugins.bluetooth.BluetoothPluginFactory;
+import net.sf.briar.plugins.droidtooth.DroidtoothPluginFactory;
+import net.sf.briar.plugins.file.RemovableDrivePluginFactory;
+import net.sf.briar.plugins.modem.ModemPluginFactory;
+import net.sf.briar.plugins.tcp.LanTcpPluginFactory;
+import net.sf.briar.plugins.tcp.WanTcpPluginFactory;
+import net.sf.briar.plugins.tor.TorPluginFactory;
+import net.sf.briar.util.OsUtils;
+import android.content.Context;
 
 import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
 import com.google.inject.Singleton;
 
 public class PluginsModule extends AbstractModule {
@@ -21,4 +40,45 @@ public class PluginsModule extends AbstractModule {
 				PluginManagerImpl.class).in(Singleton.class);
 		bind(Poller.class).to(PollerImpl.class);
 	}
+
+	@Provides
+	SimplexPluginConfig getSimplexPluginConfig(
+			@PluginExecutor Executor pluginExecutor) {
+		final Collection<SimplexPluginFactory> factories =
+				new ArrayList<SimplexPluginFactory>();
+		if(!OsUtils.isAndroid()) {
+			// No simplex plugins for Android
+		} else {
+			factories.add(new RemovableDrivePluginFactory(pluginExecutor));
+		}
+		return new SimplexPluginConfig() {
+			public Collection<SimplexPluginFactory> getFactories() {
+				return factories;
+			}
+		};
+	}
+
+	@Provides
+	DuplexPluginConfig getDuplexPluginConfig(
+			@PluginExecutor Executor pluginExecutor,
+			AndroidExecutor androidExecutor, Context appContext,
+			ShutdownManager shutdownManager) {
+		final Collection<DuplexPluginFactory> factories =
+				new ArrayList<DuplexPluginFactory>();
+		if(OsUtils.isAndroid()) {
+			factories.add(new DroidtoothPluginFactory(pluginExecutor,
+					androidExecutor, appContext));
+		} else {
+			factories.add(new BluetoothPluginFactory(pluginExecutor));
+			factories.add(new ModemPluginFactory(pluginExecutor));
+		}
+		factories.add(new LanTcpPluginFactory(pluginExecutor));
+		factories.add(new WanTcpPluginFactory(pluginExecutor, shutdownManager));
+		factories.add(new TorPluginFactory(pluginExecutor));
+		return new DuplexPluginConfig() {
+			public Collection<DuplexPluginFactory> getFactories() {
+				return factories;
+			}
+		};
+	}
 }
diff --git a/briar-core/src/net/sf/briar/plugins/bluetooth/BluetoothPluginFactory.java b/briar-core/src/net/sf/briar/plugins/bluetooth/BluetoothPluginFactory.java
index 20f07008d8..86f721a17e 100644
--- a/briar-core/src/net/sf/briar/plugins/bluetooth/BluetoothPluginFactory.java
+++ b/briar-core/src/net/sf/briar/plugins/bluetooth/BluetoothPluginFactory.java
@@ -2,27 +2,28 @@ package net.sf.briar.plugins.bluetooth;
 
 import java.util.concurrent.Executor;
 
-import net.sf.briar.api.android.AndroidExecutor;
 import net.sf.briar.api.clock.SystemClock;
-import net.sf.briar.api.lifecycle.ShutdownManager;
 import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.plugins.duplex.DuplexPlugin;
 import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
 import net.sf.briar.api.plugins.duplex.DuplexPluginFactory;
 import net.sf.briar.api.protocol.TransportId;
-import android.content.Context;
 
 public class BluetoothPluginFactory implements DuplexPluginFactory {
 
 	private static final long POLLING_INTERVAL = 3L * 60L * 1000L; // 3 mins
 
+	private final Executor pluginExecutor;
+
+	public BluetoothPluginFactory(@PluginExecutor Executor pluginExecutor) {
+		this.pluginExecutor = pluginExecutor;
+	}
+
 	public TransportId getId() {
 		return BluetoothPlugin.ID;
 	}
 
-	public DuplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
-			AndroidExecutor androidExecutor, Context appContext,
-			ShutdownManager shutdownManager, DuplexPluginCallback callback) {
+	public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
 		return new BluetoothPlugin(pluginExecutor, new SystemClock(), callback,
 				POLLING_INTERVAL);
 	}
diff --git a/briar-core/src/net/sf/briar/plugins/droidtooth/DroidtoothPluginFactory.java b/briar-core/src/net/sf/briar/plugins/droidtooth/DroidtoothPluginFactory.java
index 86244f0a1a..cb9d0e1f64 100644
--- a/briar-core/src/net/sf/briar/plugins/droidtooth/DroidtoothPluginFactory.java
+++ b/briar-core/src/net/sf/briar/plugins/droidtooth/DroidtoothPluginFactory.java
@@ -3,7 +3,6 @@ package net.sf.briar.plugins.droidtooth;
 import java.util.concurrent.Executor;
 
 import net.sf.briar.api.android.AndroidExecutor;
-import net.sf.briar.api.lifecycle.ShutdownManager;
 import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.plugins.duplex.DuplexPlugin;
 import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
@@ -15,13 +14,22 @@ public class DroidtoothPluginFactory implements DuplexPluginFactory {
 
 	private static final long POLLING_INTERVAL = 3L * 60L * 1000L; // 3 mins
 
+	private final Executor pluginExecutor;
+	private final AndroidExecutor androidExecutor;
+	private final Context appContext;
+
+	public DroidtoothPluginFactory(@PluginExecutor Executor pluginExecutor,
+			AndroidExecutor androidExecutor, Context appContext) {
+		this.pluginExecutor = pluginExecutor;
+		this.androidExecutor = androidExecutor;
+		this.appContext = appContext;
+	}
+
 	public TransportId getId() {
 		return DroidtoothPlugin.ID;
 	}
 
-	public DuplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
-			AndroidExecutor androidExecutor, Context appContext,
-			ShutdownManager shutdownManager, DuplexPluginCallback callback) {
+	public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
 		return new DroidtoothPlugin(pluginExecutor, androidExecutor, appContext,
 				callback, POLLING_INTERVAL);
 	}
diff --git a/briar-core/src/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java b/briar-core/src/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java
index 833e131bae..3a36160a17 100644
--- a/briar-core/src/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java
+++ b/briar-core/src/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java
@@ -2,27 +2,29 @@ package net.sf.briar.plugins.file;
 
 import java.util.concurrent.Executor;
 
-import net.sf.briar.api.android.AndroidExecutor;
-import net.sf.briar.api.lifecycle.ShutdownManager;
 import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.plugins.simplex.SimplexPlugin;
 import net.sf.briar.api.plugins.simplex.SimplexPluginCallback;
 import net.sf.briar.api.plugins.simplex.SimplexPluginFactory;
 import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.util.OsUtils;
-import android.content.Context;
 
 public class RemovableDrivePluginFactory implements SimplexPluginFactory {
 
 	private static final long POLLING_INTERVAL = 10L * 1000L; // 10 seconds
 
+	private final Executor pluginExecutor;
+
+	public RemovableDrivePluginFactory(
+			@PluginExecutor Executor pluginExecutor) {
+		this.pluginExecutor = pluginExecutor;
+	}
+
 	public TransportId getId() {
 		return RemovableDrivePlugin.ID;
 	}
 
-	public SimplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
-			AndroidExecutor androidExecutor, Context appContext,
-			ShutdownManager shutdownManager, SimplexPluginCallback callback) {
+	public SimplexPlugin createPlugin(SimplexPluginCallback callback) {
 		RemovableDriveFinder finder;
 		RemovableDriveMonitor monitor;
 		if(OsUtils.isLinux()) {
diff --git a/briar-core/src/net/sf/briar/plugins/modem/ModemPluginFactory.java b/briar-core/src/net/sf/briar/plugins/modem/ModemPluginFactory.java
index 2b17f1d631..8d7bb69330 100644
--- a/briar-core/src/net/sf/briar/plugins/modem/ModemPluginFactory.java
+++ b/briar-core/src/net/sf/briar/plugins/modem/ModemPluginFactory.java
@@ -2,8 +2,6 @@ package net.sf.briar.plugins.modem;
 
 import java.util.concurrent.Executor;
 
-import net.sf.briar.api.android.AndroidExecutor;
-import net.sf.briar.api.lifecycle.ShutdownManager;
 import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.plugins.duplex.DuplexPlugin;
 import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
@@ -12,19 +10,21 @@ import net.sf.briar.api.protocol.TransportId;
 
 import org.h2.util.StringUtils;
 
-import android.content.Context;
-
 public class ModemPluginFactory implements DuplexPluginFactory {
 
 	private static final long POLLING_INTERVAL = 60L * 60L * 1000L; // 1 hour
 
+	private final Executor pluginExecutor;
+
+	public ModemPluginFactory(@PluginExecutor Executor pluginExecutor) {
+		this.pluginExecutor = pluginExecutor;
+	}
+
 	public TransportId getId() {
 		return ModemPlugin.ID;
 	}
 
-	public DuplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
-			AndroidExecutor androidExecutor, Context appContext,
-			ShutdownManager shutdownManager, DuplexPluginCallback callback) {
+	public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
 		// This plugin is not enabled by default
 		String enabled = callback.getConfig().get("enabled");
 		if(StringUtils.isNullOrEmpty(enabled)) return null;
diff --git a/briar-core/src/net/sf/briar/plugins/tcp/LanTcpPluginFactory.java b/briar-core/src/net/sf/briar/plugins/tcp/LanTcpPluginFactory.java
index d3ff4eca24..81aa97848e 100644
--- a/briar-core/src/net/sf/briar/plugins/tcp/LanTcpPluginFactory.java
+++ b/briar-core/src/net/sf/briar/plugins/tcp/LanTcpPluginFactory.java
@@ -2,26 +2,27 @@ package net.sf.briar.plugins.tcp;
 
 import java.util.concurrent.Executor;
 
-import net.sf.briar.api.android.AndroidExecutor;
-import net.sf.briar.api.lifecycle.ShutdownManager;
 import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.plugins.duplex.DuplexPlugin;
 import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
 import net.sf.briar.api.plugins.duplex.DuplexPluginFactory;
 import net.sf.briar.api.protocol.TransportId;
-import android.content.Context;
 
 public class LanTcpPluginFactory implements DuplexPluginFactory {
 
 	private static final long POLLING_INTERVAL = 60L * 1000L; // 1 minute
 
+	private final Executor pluginExecutor;
+
+	public LanTcpPluginFactory(@PluginExecutor Executor pluginExecutor) {
+		this.pluginExecutor = pluginExecutor;
+	}
+
 	public TransportId getId() {
 		return LanTcpPlugin.ID;
 	}
 
-	public DuplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
-			AndroidExecutor androidExecutor, Context appContext,
-			ShutdownManager shutdownManager, DuplexPluginCallback callback) {
+	public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
 		return new LanTcpPlugin(pluginExecutor, callback, POLLING_INTERVAL);
 	}
 }
diff --git a/briar-core/src/net/sf/briar/plugins/tcp/WanTcpPluginFactory.java b/briar-core/src/net/sf/briar/plugins/tcp/WanTcpPluginFactory.java
index d280a23f77..f40d357dc1 100644
--- a/briar-core/src/net/sf/briar/plugins/tcp/WanTcpPluginFactory.java
+++ b/briar-core/src/net/sf/briar/plugins/tcp/WanTcpPluginFactory.java
@@ -2,26 +2,31 @@ package net.sf.briar.plugins.tcp;
 
 import java.util.concurrent.Executor;
 
-import net.sf.briar.api.android.AndroidExecutor;
 import net.sf.briar.api.lifecycle.ShutdownManager;
 import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.plugins.duplex.DuplexPlugin;
 import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
 import net.sf.briar.api.plugins.duplex.DuplexPluginFactory;
 import net.sf.briar.api.protocol.TransportId;
-import android.content.Context;
 
 public class WanTcpPluginFactory implements DuplexPluginFactory {
 
 	private static final long POLLING_INTERVAL = 5L * 60L * 1000L; // 5 minutes
 
+	private final Executor pluginExecutor;
+	private final ShutdownManager shutdownManager;
+
+	public WanTcpPluginFactory(@PluginExecutor Executor pluginExecutor,
+			ShutdownManager shutdownManager) {
+		this.pluginExecutor = pluginExecutor;
+		this.shutdownManager = shutdownManager;
+	}
+
 	public TransportId getId() {
 		return WanTcpPlugin.ID;
 	}
 
-	public DuplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
-			AndroidExecutor androidExecutor, Context appContext,
-			ShutdownManager shutdownManager, DuplexPluginCallback callback) {
+	public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
 		return new WanTcpPlugin(pluginExecutor, callback, POLLING_INTERVAL,
 				new PortMapperImpl(shutdownManager));
 	}
diff --git a/briar-core/src/net/sf/briar/plugins/tor/TorPluginFactory.java b/briar-core/src/net/sf/briar/plugins/tor/TorPluginFactory.java
index 8430fd9a27..c87bdef779 100644
--- a/briar-core/src/net/sf/briar/plugins/tor/TorPluginFactory.java
+++ b/briar-core/src/net/sf/briar/plugins/tor/TorPluginFactory.java
@@ -2,8 +2,6 @@ package net.sf.briar.plugins.tor;
 
 import java.util.concurrent.Executor;
 
-import net.sf.briar.api.android.AndroidExecutor;
-import net.sf.briar.api.lifecycle.ShutdownManager;
 import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.plugins.duplex.DuplexPlugin;
 import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
@@ -12,19 +10,21 @@ import net.sf.briar.api.protocol.TransportId;
 
 import org.h2.util.StringUtils;
 
-import android.content.Context;
-
 public class TorPluginFactory implements DuplexPluginFactory {
 
 	private static final long POLLING_INTERVAL = 15L * 60L * 1000L; // 15 mins
 
+	private final Executor pluginExecutor;
+
+	public TorPluginFactory(@PluginExecutor Executor pluginExecutor) {
+		this.pluginExecutor = pluginExecutor;
+	}
+
 	public TransportId getId() {
 		return TorPlugin.ID;
 	}
 
-	public DuplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
-			AndroidExecutor androidExecutor, Context appContext,
-			ShutdownManager shutdownManager, DuplexPluginCallback callback) {
+	public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
 		// This plugin is not enabled by default
 		String enabled = callback.getConfig().get("enabled");
 		if(StringUtils.isNullOrEmpty(enabled)) return null;
diff --git a/briar-tests/src/net/sf/briar/plugins/PluginManagerImplTest.java b/briar-tests/src/net/sf/briar/plugins/PluginManagerImplTest.java
index f7bad8c34e..3c958e1013 100644
--- a/briar-tests/src/net/sf/briar/plugins/PluginManagerImplTest.java
+++ b/briar-tests/src/net/sf/briar/plugins/PluginManagerImplTest.java
@@ -1,5 +1,6 @@
 package net.sf.briar.plugins;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -9,10 +10,15 @@ import net.sf.briar.api.TransportConfig;
 import net.sf.briar.api.TransportProperties;
 import net.sf.briar.api.android.AndroidExecutor;
 import net.sf.briar.api.db.DatabaseComponent;
-import net.sf.briar.api.lifecycle.ShutdownManager;
+import net.sf.briar.api.plugins.duplex.DuplexPluginConfig;
+import net.sf.briar.api.plugins.duplex.DuplexPluginFactory;
+import net.sf.briar.api.plugins.simplex.SimplexPluginConfig;
+import net.sf.briar.api.plugins.simplex.SimplexPluginFactory;
 import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.transport.ConnectionDispatcher;
 import net.sf.briar.api.ui.UiCallback;
+import net.sf.briar.plugins.file.RemovableDrivePluginFactory;
+import net.sf.briar.plugins.tcp.LanTcpPluginFactory;
 
 import org.jmock.Expectations;
 import org.jmock.Mockery;
@@ -24,17 +30,30 @@ public class PluginManagerImplTest extends BriarTestCase {
 	@Test
 	public void testStartAndStop() throws Exception {
 		Mockery context = new Mockery();
+		final ExecutorService pluginExecutor = Executors.newCachedThreadPool();
 		final AndroidExecutor androidExecutor =
 				context.mock(AndroidExecutor.class);
-		final ShutdownManager shutdownManager =
-				context.mock(ShutdownManager.class);
+		final SimplexPluginConfig simplexPluginConfig =
+				context.mock(SimplexPluginConfig.class);
+		final DuplexPluginConfig duplexPluginConfig =
+				context.mock(DuplexPluginConfig.class);
 		final DatabaseComponent db = context.mock(DatabaseComponent.class);
 		final Poller poller = context.mock(Poller.class);
 		final ConnectionDispatcher dispatcher =
 				context.mock(ConnectionDispatcher.class);
 		final UiCallback uiCallback = context.mock(UiCallback.class);
+		// One simplex plugin
+		final SimplexPluginFactory removableDrive =
+				new RemovableDrivePluginFactory(pluginExecutor);
+		// One duplex plugin
+		final DuplexPluginFactory lanTcp =
+				new LanTcpPluginFactory(pluginExecutor);
 		context.checking(new Expectations() {{
 			// Start
+			oneOf(simplexPluginConfig).getFactories();
+			will(returnValue(Arrays.asList(removableDrive)));
+			oneOf(duplexPluginConfig).getFactories();
+			will(returnValue(Arrays.asList(lanTcp)));
 			oneOf(poller).start(with(any(Collection.class)));
 			allowing(db).getConfig(with(any(TransportId.class)));
 			will(returnValue(new TransportConfig()));
@@ -48,16 +67,12 @@ public class PluginManagerImplTest extends BriarTestCase {
 			oneOf(poller).stop();
 			oneOf(androidExecutor).shutdown();
 		}});
-		ExecutorService executor = Executors.newCachedThreadPool();
-		PluginManagerImpl p = new PluginManagerImpl(executor, androidExecutor,
-				shutdownManager, db, poller, dispatcher, uiCallback);
-		// We expect either 3 or 4 plugins to be started, depending on whether
-		// the test machine has a Bluetooth device
-		int started = p.start(null);
-		int stopped = p.stop();
-		assertEquals(started, stopped);
-		assertTrue(started >= 3);
-		assertTrue(started <= 4);
+		PluginManagerImpl p = new PluginManagerImpl(pluginExecutor,
+				androidExecutor, simplexPluginConfig, duplexPluginConfig, db,
+				poller, dispatcher, uiCallback);
+		// Two plugins should be started and stopped
+		assertEquals(2, p.start(null));
+		assertEquals(2, p.stop());
 		context.assertIsSatisfied();
 	}
 }
-- 
GitLab