diff --git a/briar-android/src/org/briarproject/plugins/AndroidPluginsModule.java b/briar-android/src/org/briarproject/plugins/AndroidPluginsModule.java
index 4ebf3886e5d60bf67cbdb8a2480029902fa6d638..ca899bc8aed4e8a67cc0c13e3619426cbedd4c2a 100644
--- a/briar-android/src/org/briarproject/plugins/AndroidPluginsModule.java
+++ b/briar-android/src/org/briarproject/plugins/AndroidPluginsModule.java
@@ -38,7 +38,7 @@ public class AndroidPluginsModule {
 		DuplexPluginFactory bluetooth = new DroidtoothPluginFactory(ioExecutor,
 				androidExecutor, appContext, random, backoffFactory);
 		DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, appContext,
-				locationUtils, reporter, eventBus);
+				locationUtils, reporter, eventBus, backoffFactory);
 		DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
 				backoffFactory, appContext);
 		final Collection<DuplexPluginFactory> duplex =
diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java
index ee7acf26ba47c4fb39128f3eede571189c39e4f7..7bc16525ac0907e75839c8205c0329cfe6bfea9a 100644
--- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java
+++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java
@@ -16,8 +16,8 @@ import java.util.concurrent.Executor;
 public class DroidtoothPluginFactory implements DuplexPluginFactory {
 
 	private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
-	private static final int MIN_POLLING_INTERVAL = 2 * 60 * 1000; // 2 minutes
-	private static final int MAX_POLLING_INTERVAL = 60 * 60 * 1000; // 1 hour
+	private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
+	private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
 	private static final double BACKOFF_BASE = 1.2;
 
 	private final Executor ioExecutor;
@@ -36,14 +36,17 @@ public class DroidtoothPluginFactory implements DuplexPluginFactory {
 		this.backoffFactory = backoffFactory;
 	}
 
+	@Override
 	public TransportId getId() {
 		return DroidtoothPlugin.ID;
 	}
 
+	@Override
 	public int getMaxLatency() {
 		return MAX_LATENCY;
 	}
 
+	@Override
 	public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
 		Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
 				MAX_POLLING_INTERVAL, BACKOFF_BASE);
diff --git a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java
index 16d456ad3b22e47a2e128e45afd55705dccba3dc..50ee377b84516ed0bf3eb3a8e29663878b8439d2 100644
--- a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java
+++ b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java
@@ -15,8 +15,8 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
 
 	private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
 	private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
-	private static final int MIN_POLLING_INTERVAL = 2 * 60 * 1000; // 2 minutes
-	private static final int MAX_POLLING_INTERVAL = 60 * 60 * 1000; // 1 hour
+	private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
+	private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
 	private static final double BACKOFF_BASE = 1.2;
 
 	private final Executor ioExecutor;
@@ -30,14 +30,17 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
 		this.appContext = appContext;
 	}
 
+	@Override
 	public TransportId getId() {
 		return LanTcpPlugin.ID;
 	}
 
+	@Override
 	public int getMaxLatency() {
 		return MAX_LATENCY;
 	}
 
+	@Override
 	public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
 		Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
 				MAX_POLLING_INTERVAL, BACKOFF_BASE);
diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
index e7852bff66fe9340f3c16b4d6f3744f0913ae88e..19499171b2279cfb18510382618d787586c459c5 100644
--- a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
+++ b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
@@ -23,13 +23,13 @@ import org.briarproject.api.event.EventListener;
 import org.briarproject.api.event.SettingsUpdatedEvent;
 import org.briarproject.api.keyagreement.KeyAgreementListener;
 import org.briarproject.api.keyagreement.TransportDescriptor;
+import org.briarproject.api.plugins.Backoff;
 import org.briarproject.api.plugins.duplex.DuplexPlugin;
 import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
 import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
 import org.briarproject.api.properties.TransportProperties;
 import org.briarproject.api.reporting.DevReporter;
 import org.briarproject.api.settings.Settings;
-import org.briarproject.api.system.Clock;
 import org.briarproject.api.system.LocationUtils;
 import org.briarproject.util.StringUtils;
 
@@ -79,7 +79,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 	private static final int SOCKS_PORT = 59050, CONTROL_PORT = 59051;
 	private static final int COOKIE_TIMEOUT = 3000; // Milliseconds
 	private static final Pattern ONION = Pattern.compile("[a-z2-7]{16}");
-	private static final int MIN_DESCRIPTORS_PUBLISHED = 3;
 	private static final Logger LOG =
 			Logger.getLogger(TorPlugin.class.getName());
 
@@ -87,10 +86,10 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 	private final Context appContext;
 	private final LocationUtils locationUtils;
 	private final DevReporter reporter;
-	private final Clock clock;
+	private final Backoff backoff;
 	private final DuplexPluginCallback callback;
 	private final String architecture;
-	private final int maxLatency, maxIdleTime, pollingInterval, socketTimeout;
+	private final int maxLatency, maxIdleTime, socketTimeout;
 	private final ConnectionStatus connectionStatus;
 	private final File torDirectory, torFile, geoIpFile, configFile;
 	private final File doneFile, cookieFile;
@@ -103,23 +102,22 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 	private volatile BroadcastReceiver networkStateReceiver = null;
 
 	TorPlugin(Executor ioExecutor, Context appContext,
-			LocationUtils locationUtils, DevReporter reporter, Clock clock,
+			LocationUtils locationUtils, DevReporter reporter, Backoff backoff,
 			DuplexPluginCallback callback, String architecture, int maxLatency,
-			int maxIdleTime, int pollingInterval) {
+			int maxIdleTime) {
 		this.ioExecutor = ioExecutor;
 		this.appContext = appContext;
 		this.locationUtils = locationUtils;
 		this.reporter = reporter;
-		this.clock = clock;
+		this.backoff = backoff;
 		this.callback = callback;
 		this.architecture = architecture;
 		this.maxLatency = maxLatency;
 		this.maxIdleTime = maxIdleTime;
-		this.pollingInterval = pollingInterval;
 		if (maxIdleTime > Integer.MAX_VALUE / 2)
 			socketTimeout = Integer.MAX_VALUE;
 		else socketTimeout = maxIdleTime * 2;
-		connectionStatus = new ConnectionStatus(pollingInterval);
+		connectionStatus = new ConnectionStatus();
 		torDirectory = appContext.getDir("tor", MODE_PRIVATE);
 		torFile = new File(torDirectory, "tor");
 		geoIpFile = new File(torDirectory, "geoip");
@@ -228,7 +226,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 			if (phase != null && phase.contains("PROGRESS=100")) {
 				LOG.info("Tor has already bootstrapped");
 				connectionStatus.setBootstrapped();
-				sendCrashReports();
+				sendDevReports();
 			}
 		}
 		// Register to receive network status events
@@ -359,12 +357,12 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 		}
 	}
 
-	private void sendCrashReports() {
+	private void sendDevReports() {
 		ioExecutor.execute(new Runnable() {
 			@Override
 			public void run() {
-				reporter.sendReports(
-						AndroidUtils.getReportDir(appContext), SOCKS_PORT);
+				File reportDir = AndroidUtils.getReportDir(appContext);
+				reporter.sendReports(reportDir, SOCKS_PORT);
 			}
 		});
 	}
@@ -404,6 +402,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 						publishHiddenService(localPort);
 					}
 				});
+				backoff.reset();
 				// Accept incoming hidden service connections from Tor
 				acceptContactConnections(ss);
 			}
@@ -470,6 +469,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 				return;
 			}
 			LOG.info("Connection received");
+			backoff.reset();
 			TorTransportConnection conn = new TorTransportConnection(this, s);
 			callback.incomingConnectionCreated(conn);
 		}
@@ -517,25 +517,25 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 	}
 
 	public int getPollingInterval() {
-		return pollingInterval;
+		return backoff.getPollingInterval();
 	}
 
 	public void poll(Collection<ContactId> connected) {
 		if (!isRunning()) return;
-		if (connectionStatus.shouldPoll(clock.currentTimeMillis())) {
-			// TODO: Pass properties to connectAndCallBack()
-			for (ContactId c : callback.getRemoteProperties().keySet())
-				if (!connected.contains(c)) connectAndCallBack(c);
-		} else {
-			LOG.info("Hidden service descriptor published, not polling");
-		}
+		backoff.increment();
+		// TODO: Pass properties to connectAndCallBack()
+		for (ContactId c : callback.getRemoteProperties().keySet())
+			if (!connected.contains(c)) connectAndCallBack(c);
 	}
 
 	private void connectAndCallBack(final ContactId c) {
 		ioExecutor.execute(new Runnable() {
 			public void run() {
 				DuplexTransportConnection d = createConnection(c);
-				if (d != null) callback.outgoingConnectionCreated(c, d);
+				if (d != null) {
+					backoff.reset();
+					callback.outgoingConnectionCreated(c, d);
+				}
 			}
 		});
 	}
@@ -561,7 +561,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 			return new TorTransportConnection(this, s);
 		} catch (IOException e) {
 			if (LOG.isLoggable(INFO))
-				LOG.log(INFO, "Could not connect to " + onion + ": ", e);
+				LOG.info("Could not connect to " + onion + ": " + e.toString());
 			return null;
 		}
 	}
@@ -593,6 +593,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 		if (status.equals("BUILT") &&
 				connectionStatus.getAndSetCircuitBuilt()) {
 			LOG.info("First circuit built");
+			backoff.reset();
 			if (isRunning()) callback.transportEnabled();
 		}
 	}
@@ -614,14 +615,15 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 		if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg);
 		if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
 			connectionStatus.setBootstrapped();
-			sendCrashReports();
+			sendDevReports();
+			backoff.reset();
 			if (isRunning()) callback.transportEnabled();
 		}
 	}
 
 	public void unrecognized(String type, String msg) {
 		if (type.equals("HS_DESC") && msg.startsWith("UPLOADED"))
-			connectionStatus.descriptorPublished(clock.currentTimeMillis());
+			LOG.info("Descriptor uploaded");
 	}
 
 	private static class WriteObserver extends FileObserver {
@@ -707,17 +709,9 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 
 	private static class ConnectionStatus {
 
-		private final int pollingInterval;
-
 		// All of the following are locking: this
 		private boolean networkEnabled = false;
 		private boolean bootstrapped = false, circuitBuilt = false;
-		private int descriptorsPublished = 0;
-		private long descriptorsPublishedTime = Long.MAX_VALUE;
-
-		private ConnectionStatus(int pollingInterval) {
-			this.pollingInterval = pollingInterval;
-		}
 
 		private synchronized void setBootstrapped() {
 			bootstrapped = true;
@@ -729,26 +723,13 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 			return firstCircuit;
 		}
 
-		private synchronized void descriptorPublished(long now) {
-			descriptorsPublished++;
-			if (descriptorsPublished == MIN_DESCRIPTORS_PUBLISHED)
-				descriptorsPublishedTime = now;
-		}
-
 		private synchronized void enableNetwork(boolean enable) {
 			networkEnabled = enable;
 			circuitBuilt = false;
-			descriptorsPublished = 0;
-			descriptorsPublishedTime = Long.MAX_VALUE;
 		}
 
 		private synchronized boolean isConnected() {
 			return networkEnabled && bootstrapped && circuitBuilt;
 		}
-
-		private synchronized boolean shouldPoll(long now) {
-			return descriptorsPublished < MIN_DESCRIPTORS_PUBLISHED
-					|| now - descriptorsPublishedTime < 2 * pollingInterval;
-		}
 	}
 }
diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java b/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java
index edf0103da9fed1cb4ad300377d1044aad3097eee..9cfabc3cb5a42e1833948920b752ce18107cccf0 100644
--- a/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java
+++ b/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java
@@ -6,13 +6,13 @@ import android.os.Build;
 import org.briarproject.android.util.AndroidUtils;
 import org.briarproject.api.TransportId;
 import org.briarproject.api.event.EventBus;
+import org.briarproject.api.plugins.Backoff;
+import org.briarproject.api.plugins.BackoffFactory;
 import org.briarproject.api.plugins.duplex.DuplexPlugin;
 import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
 import org.briarproject.api.plugins.duplex.DuplexPluginFactory;
 import org.briarproject.api.reporting.DevReporter;
-import org.briarproject.api.system.Clock;
 import org.briarproject.api.system.LocationUtils;
-import org.briarproject.system.SystemClock;
 
 import java.util.concurrent.Executor;
 import java.util.logging.Logger;
@@ -24,34 +24,39 @@ public class TorPluginFactory implements DuplexPluginFactory {
 
 	private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
 	private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
-	private static final int POLLING_INTERVAL = 2 * 60 * 1000; // 2 minutes
+	private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
+	private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
+	private static final double BACKOFF_BASE = 1.2;
 
 	private final Executor ioExecutor;
 	private final Context appContext;
 	private final LocationUtils locationUtils;
 	private final DevReporter reporter;
 	private final EventBus eventBus;
-	private final Clock clock;
+	private final BackoffFactory backoffFactory;
 
 	public TorPluginFactory(Executor ioExecutor, Context appContext,
 			LocationUtils locationUtils, DevReporter reporter,
-			EventBus eventBus) {
+			EventBus eventBus, BackoffFactory backoffFactory) {
 		this.ioExecutor = ioExecutor;
 		this.appContext = appContext;
 		this.locationUtils = locationUtils;
 		this.reporter = reporter;
 		this.eventBus = eventBus;
-		clock = new SystemClock();
+		this.backoffFactory = backoffFactory;
 	}
 
+	@Override
 	public TransportId getId() {
 		return TorPlugin.ID;
 	}
 
+	@Override
 	public int getMaxLatency() {
 		return MAX_LATENCY;
 	}
 
+	@Override
 	public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
 
 		// Check that we have a Tor binary for this architecture
@@ -72,10 +77,11 @@ public class TorPluginFactory implements DuplexPluginFactory {
 		// Use position-independent executable for SDK >= 16
 		if (Build.VERSION.SDK_INT >= 16) architecture += "-pie";
 
-		TorPlugin plugin =
-				new TorPlugin(ioExecutor, appContext, locationUtils, reporter,
-						clock, callback, architecture, MAX_LATENCY,
-						MAX_IDLE_TIME, POLLING_INTERVAL);
+		Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
+				MAX_POLLING_INTERVAL, BACKOFF_BASE);
+		TorPlugin plugin = new TorPlugin(ioExecutor, appContext, locationUtils,
+				reporter, backoff, callback, architecture, MAX_LATENCY,
+				MAX_IDLE_TIME);
 		eventBus.addListener(plugin);
 		return plugin;
 	}
diff --git a/briar-api/src/org/briarproject/api/event/ConnectionClosedEvent.java b/briar-api/src/org/briarproject/api/event/ConnectionClosedEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..29030edcc4e382b0aa3392823fc51fe7a1ec2862
--- /dev/null
+++ b/briar-api/src/org/briarproject/api/event/ConnectionClosedEvent.java
@@ -0,0 +1,30 @@
+package org.briarproject.api.event;
+
+import org.briarproject.api.TransportId;
+import org.briarproject.api.contact.ContactId;
+
+public class ConnectionClosedEvent extends Event {
+
+	private final ContactId contactId;
+	private final TransportId transportId;
+	private final boolean incoming;
+
+	public ConnectionClosedEvent(ContactId contactId, TransportId transportId,
+			boolean incoming) {
+		this.contactId = contactId;
+		this.transportId = transportId;
+		this.incoming = incoming;
+	}
+
+	public ContactId getContactId() {
+		return contactId;
+	}
+
+	public TransportId getTransportId() {
+		return transportId;
+	}
+
+	public boolean isIncoming() {
+		return incoming;
+	}
+}
diff --git a/briar-api/src/org/briarproject/api/event/ConnectionOpenedEvent.java b/briar-api/src/org/briarproject/api/event/ConnectionOpenedEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..2143eb37a035b4e79c7887354cc38115b891cdfb
--- /dev/null
+++ b/briar-api/src/org/briarproject/api/event/ConnectionOpenedEvent.java
@@ -0,0 +1,30 @@
+package org.briarproject.api.event;
+
+import org.briarproject.api.TransportId;
+import org.briarproject.api.contact.ContactId;
+
+public class ConnectionOpenedEvent extends Event {
+
+	private final ContactId contactId;
+	private final TransportId transportId;
+	private final boolean incoming;
+
+	public ConnectionOpenedEvent(ContactId contactId, TransportId transportId,
+			boolean incoming) {
+		this.contactId = contactId;
+		this.transportId = transportId;
+		this.incoming = incoming;
+	}
+
+	public ContactId getContactId() {
+		return contactId;
+	}
+
+	public TransportId getTransportId() {
+		return transportId;
+	}
+
+	public boolean isIncoming() {
+		return incoming;
+	}
+}
diff --git a/briar-api/src/org/briarproject/api/plugins/ConnectionRegistry.java b/briar-api/src/org/briarproject/api/plugins/ConnectionRegistry.java
index dc9376195387a5da851a9aab37a67707bc470e1c..6afc50acecd28015f61e0c92502faffdaae28ad9 100644
--- a/briar-api/src/org/briarproject/api/plugins/ConnectionRegistry.java
+++ b/briar-api/src/org/briarproject/api/plugins/ConnectionRegistry.java
@@ -10,9 +10,9 @@ import java.util.Collection;
  */
 public interface ConnectionRegistry {
 
-	void registerConnection(ContactId c, TransportId t);
+	void registerConnection(ContactId c, TransportId t, boolean incoming);
 
-	void unregisterConnection(ContactId c, TransportId t);
+	void unregisterConnection(ContactId c, TransportId t, boolean incoming);
 
 	Collection<ContactId> getConnectedContacts(TransportId t);
 
diff --git a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java
index 3c9f5fb48ed3d792a8180ae93bd5e8cc1e04e0eb..c85c5f016d64c3af085454ca856d240943f0b93f 100644
--- a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java
+++ b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java
@@ -144,7 +144,7 @@ class ConnectionManagerImpl implements ConnectionManager {
 				return;
 			}
 			ContactId contactId = ctx.getContactId();
-			connectionRegistry.registerConnection(contactId, transportId);
+			connectionRegistry.registerConnection(contactId, transportId, true);
 			try {
 				// Create and run the incoming session
 				createIncomingSession(ctx, reader).run();
@@ -153,7 +153,8 @@ class ConnectionManagerImpl implements ConnectionManager {
 				if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
 				disposeReader(true, true);
 			} finally {
-				connectionRegistry.unregisterConnection(contactId, transportId);
+				connectionRegistry.unregisterConnection(contactId, transportId,
+						true);
 			}
 		}
 
@@ -194,7 +195,8 @@ class ConnectionManagerImpl implements ConnectionManager {
 				disposeWriter(true);
 				return;
 			}
-			connectionRegistry.registerConnection(contactId, transportId);
+			connectionRegistry.registerConnection(contactId, transportId,
+					false);
 			try {
 				// Create and run the outgoing session
 				createSimplexOutgoingSession(ctx, writer).run();
@@ -203,7 +205,8 @@ class ConnectionManagerImpl implements ConnectionManager {
 				if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
 				disposeWriter(true);
 			} finally {
-				connectionRegistry.unregisterConnection(contactId, transportId);
+				connectionRegistry.unregisterConnection(contactId, transportId,
+						false);
 			}
 		}
 
@@ -254,7 +257,7 @@ class ConnectionManagerImpl implements ConnectionManager {
 				return;
 			}
 			contactId = ctx.getContactId();
-			connectionRegistry.registerConnection(contactId, transportId);
+			connectionRegistry.registerConnection(contactId, transportId, true);
 			// Start the outgoing session on another thread
 			ioExecutor.execute(new Runnable() {
 				public void run() {
@@ -270,7 +273,8 @@ class ConnectionManagerImpl implements ConnectionManager {
 				if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
 				disposeReader(true, true);
 			} finally {
-				connectionRegistry.unregisterConnection(contactId, transportId);
+				connectionRegistry.unregisterConnection(contactId, transportId,
+						true);
 			}
 		}
 
@@ -398,7 +402,8 @@ class ConnectionManagerImpl implements ConnectionManager {
 				disposeReader(true, true);
 				return;
 			}
-			connectionRegistry.registerConnection(contactId, transportId);
+			connectionRegistry.registerConnection(contactId, transportId,
+					false);
 			try {
 				// Create and run the incoming session
 				incomingSession = createIncomingSession(ctx, reader);
@@ -408,7 +413,8 @@ class ConnectionManagerImpl implements ConnectionManager {
 				if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
 				disposeReader(true, true);
 			} finally {
-				connectionRegistry.unregisterConnection(contactId, transportId);
+				connectionRegistry.unregisterConnection(contactId, transportId,
+						false);
 			}
 		}
 
diff --git a/briar-core/src/org/briarproject/plugins/ConnectionRegistryImpl.java b/briar-core/src/org/briarproject/plugins/ConnectionRegistryImpl.java
index 0fe9c3b4b4cae11e0f407d61498acd62a89b9ff9..c7f726a985c9086ebbf11d90d1efd15e8b99df93 100644
--- a/briar-core/src/org/briarproject/plugins/ConnectionRegistryImpl.java
+++ b/briar-core/src/org/briarproject/plugins/ConnectionRegistryImpl.java
@@ -2,6 +2,8 @@ package org.briarproject.plugins;
 
 import org.briarproject.api.TransportId;
 import org.briarproject.api.contact.ContactId;
+import org.briarproject.api.event.ConnectionClosedEvent;
+import org.briarproject.api.event.ConnectionOpenedEvent;
 import org.briarproject.api.event.ContactConnectedEvent;
 import org.briarproject.api.event.ContactDisconnectedEvent;
 import org.briarproject.api.event.EventBus;
@@ -40,8 +42,12 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
 		contactCounts = new HashMap<ContactId, Integer>();
 	}
 
-	public void registerConnection(ContactId c, TransportId t) {
-		if (LOG.isLoggable(INFO)) LOG.info("Connection registered: " + t);
+	public void registerConnection(ContactId c, TransportId t,
+			boolean incoming) {
+		if (LOG.isLoggable(INFO)) {
+			if (incoming) LOG.info("Incoming connection registered: " + t);
+			else LOG.info("Outgoing connection registered: " + t);
+		}
 		boolean firstConnection = false;
 		lock.lock();
 		try {
@@ -63,14 +69,19 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
 		} finally {
 			lock.unlock();
 		}
+		eventBus.broadcast(new ConnectionOpenedEvent(c, t, incoming));
 		if (firstConnection) {
 			LOG.info("Contact connected");
 			eventBus.broadcast(new ContactConnectedEvent(c));
 		}
 	}
 
-	public void unregisterConnection(ContactId c, TransportId t) {
-		if (LOG.isLoggable(INFO)) LOG.info("Connection unregistered: " + t);
+	public void unregisterConnection(ContactId c, TransportId t,
+			boolean incoming) {
+		if (LOG.isLoggable(INFO)) {
+			if (incoming) LOG.info("Incoming connection unregistered: " + t);
+			else LOG.info("Outgoing connection unregistered: " + t);
+		}
 		boolean lastConnection = false;
 		lock.lock();
 		try {
@@ -94,6 +105,7 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
 		} finally {
 			lock.unlock();
 		}
+		eventBus.broadcast(new ConnectionClosedEvent(c, t, incoming));
 		if (lastConnection) {
 			LOG.info("Contact disconnected");
 			eventBus.broadcast(new ContactDisconnectedEvent(c));
diff --git a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java
index 4eb8da75b93907cb3e5ef1a03fbea07f9e74d21c..78c3cd707006a1b9f2afb1d5eba4f689892e09f6 100644
--- a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java
+++ b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java
@@ -3,6 +3,7 @@ package org.briarproject.plugins;
 import org.briarproject.api.TransportId;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.db.DbException;
+import org.briarproject.api.event.ConnectionClosedEvent;
 import org.briarproject.api.event.ContactStatusChangedEvent;
 import org.briarproject.api.event.Event;
 import org.briarproject.api.event.EventBus;
@@ -141,10 +142,12 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 		}
 	}
 
+	@Override
 	public Plugin getPlugin(TransportId t) {
 		return plugins.get(t);
 	}
 
+	@Override
 	public Collection<DuplexPlugin> getInvitationPlugins() {
 		List<DuplexPlugin> supported = new ArrayList<DuplexPlugin>();
 		for (DuplexPlugin d : duplexPlugins)
@@ -152,6 +155,7 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 		return Collections.unmodifiableList(supported);
 	}
 
+	@Override
 	public Collection<DuplexPlugin> getKeyAgreementPlugins() {
 		List<DuplexPlugin> supported = new ArrayList<DuplexPlugin>();
 		for (DuplexPlugin d : duplexPlugins)
@@ -163,7 +167,16 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 	public void eventOccurred(Event e) {
 		if (e instanceof ContactStatusChangedEvent) {
 			ContactStatusChangedEvent c = (ContactStatusChangedEvent) e;
-			if (c.isActive()) connectToContact(c.getContactId());
+			if (c.isActive()) {
+				// Connect to the newly activated contact
+				connectToContact(c.getContactId());
+			}
+		} else if (e instanceof ConnectionClosedEvent) {
+			ConnectionClosedEvent c = (ConnectionClosedEvent) e;
+			if (!c.isIncoming()) {
+				// Connect to the disconnected contact
+				connectToContact(c.getContactId(), c.getTransportId());
+			}
 		}
 	}
 
@@ -174,8 +187,17 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 			if (d.shouldPoll()) connectToContact(c, d);
 	}
 
+	private void connectToContact(ContactId c, TransportId t) {
+		Plugin p = plugins.get(t);
+		if (p instanceof SimplexPlugin && p.shouldPoll())
+			connectToContact(c, (SimplexPlugin) p);
+		else if (p instanceof DuplexPlugin && p.shouldPoll())
+			connectToContact(c, (DuplexPlugin) p);
+	}
+
 	private void connectToContact(final ContactId c, final SimplexPlugin p) {
 		ioExecutor.execute(new Runnable() {
+			@Override
 			public void run() {
 				TransportId t = p.getId();
 				if (!connectionRegistry.isConnected(c, t)) {
@@ -189,6 +211,7 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 
 	private void connectToContact(final ContactId c, final DuplexPlugin p) {
 		ioExecutor.execute(new Runnable() {
+			@Override
 			public void run() {
 				TransportId t = p.getId();
 				if (!connectionRegistry.isConnected(c, t)) {
@@ -211,6 +234,7 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 			this.latch = latch;
 		}
 
+		@Override
 		public void run() {
 			try {
 				TransportId id = factory.getId();
@@ -230,7 +254,6 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 					if (started) {
 						plugins.put(id, plugin);
 						simplexPlugins.add(plugin);
-						if (plugin.shouldPoll()) poller.addPlugin(plugin);
 						if (LOG.isLoggable(INFO)) {
 							String name = plugin.getClass().getSimpleName();
 							LOG.info("Starting " + name + " took " +
@@ -263,6 +286,7 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 			this.latch = latch;
 		}
 
+		@Override
 		public void run() {
 			try {
 				TransportId id = factory.getId();
@@ -282,7 +306,6 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 					if (started) {
 						plugins.put(id, plugin);
 						duplexPlugins.add(plugin);
-						if (plugin.shouldPoll()) poller.addPlugin(plugin);
 						if (LOG.isLoggable(INFO)) {
 							String name = plugin.getClass().getSimpleName();
 							LOG.info("Starting " + name + " took " +
@@ -314,6 +337,7 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 			this.latch = latch;
 		}
 
+		@Override
 		public void run() {
 			try {
 				long start = System.currentTimeMillis();
@@ -339,6 +363,7 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 			this.id = id;
 		}
 
+		@Override
 		public Settings getSettings() {
 			try {
 				return settingsManager.getSettings(id.getString());
@@ -348,6 +373,7 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 			}
 		}
 
+		@Override
 		public TransportProperties getLocalProperties() {
 			try {
 				TransportProperties p =
@@ -359,6 +385,7 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 			}
 		}
 
+		@Override
 		public Map<ContactId, TransportProperties> getRemoteProperties() {
 			try {
 				return transportPropertyManager.getRemoteProperties(id);
@@ -368,6 +395,7 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 			}
 		}
 
+		@Override
 		public void mergeSettings(Settings s) {
 			try {
 				settingsManager.mergeSettings(s, id.getString());
@@ -376,6 +404,7 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 			}
 		}
 
+		@Override
 		public void mergeLocalProperties(TransportProperties p) {
 			try {
 				transportPropertyManager.mergeLocalProperties(id, p);
@@ -384,24 +413,29 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 			}
 		}
 
+		@Override
 		public int showChoice(String[] options, String... message) {
 			return uiCallback.showChoice(options, message);
 		}
 
+		@Override
 		public boolean showConfirmationMessage(String... message) {
 			return uiCallback.showConfirmationMessage(message);
 		}
 
+		@Override
 		public void showMessage(String... message) {
 			uiCallback.showMessage(message);
 		}
 
+		@Override
 		public void transportEnabled() {
 			eventBus.broadcast(new TransportEnabledEvent(id));
 			Plugin p = plugins.get(id);
 			if (p != null) poller.pollNow(p);
 		}
 
+		@Override
 		public void transportDisabled() {
 			eventBus.broadcast(new TransportDisabledEvent(id));
 		}
@@ -414,10 +448,12 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 			super(id);
 		}
 
+		@Override
 		public void readerCreated(TransportConnectionReader r) {
 			connectionManager.manageIncomingConnection(id, r);
 		}
 
+		@Override
 		public void writerCreated(ContactId c, TransportConnectionWriter w) {
 			connectionManager.manageOutgoingConnection(c, id, w);
 		}
@@ -430,10 +466,12 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
 			super(id);
 		}
 
+		@Override
 		public void incomingConnectionCreated(DuplexTransportConnection d) {
 			connectionManager.manageIncomingConnection(id, d);
 		}
 
+		@Override
 		public void outgoingConnectionCreated(ContactId c,
 				DuplexTransportConnection d) {
 			connectionManager.manageOutgoingConnection(c, id, d);
diff --git a/briar-core/src/org/briarproject/plugins/Poller.java b/briar-core/src/org/briarproject/plugins/Poller.java
index 22de0148949ee7003dfec2ef87546579f603af48..2cacf1561b0bb8a513fd3f91140eeeb9c1367170 100644
--- a/briar-core/src/org/briarproject/plugins/Poller.java
+++ b/briar-core/src/org/briarproject/plugins/Poller.java
@@ -4,9 +4,6 @@ import org.briarproject.api.plugins.Plugin;
 
 interface Poller {
 
-	/** Adds the given plugin to the collection of plugins to be polled. */
-	void addPlugin(Plugin p);
-
 	/** Tells the poller to poll the given plugin immediately. */
 	void pollNow(Plugin p);
 
diff --git a/briar-core/src/org/briarproject/plugins/PollerImpl.java b/briar-core/src/org/briarproject/plugins/PollerImpl.java
index 938997a7646d573188bd8716871c5196e10347b1..db8e1b0b8d8c85587e0696692e2890372e6c147a 100644
--- a/briar-core/src/org/briarproject/plugins/PollerImpl.java
+++ b/briar-core/src/org/briarproject/plugins/PollerImpl.java
@@ -39,25 +39,17 @@ class PollerImpl implements Poller {
 		tasks = new ConcurrentHashMap<TransportId, PollTask>();
 	}
 
+	@Override
 	public void stop() {
 		timer.cancel();
 	}
 
-	public void addPlugin(Plugin p) {
-		// Randomise first polling interval
-		if (p.shouldPoll())
-			schedule(p, randomise(p.getPollingInterval()), false);
-	}
-
+	@Override
 	public void pollNow(Plugin p) {
 		// Randomise next polling interval
 		if (p.shouldPoll()) schedule(p, 0, true);
 	}
 
-	private int randomise(int interval) {
-		return (int) (interval * random.nextDouble());
-	}
-
 	private void schedule(Plugin p, int interval, boolean randomiseNext) {
 		// Replace any previously scheduled task for this plugin
 		PollTask task = new PollTask(p, randomiseNext);
@@ -68,6 +60,7 @@ class PollerImpl implements Poller {
 
 	private void poll(final Plugin p) {
 		ioExecutor.execute(new Runnable() {
+			@Override
 			public void run() {
 				if (LOG.isLoggable(INFO))
 					LOG.info("Polling " + p.getClass().getSimpleName());
@@ -90,7 +83,8 @@ class PollerImpl implements Poller {
 		public void run() {
 			tasks.remove(plugin.getId());
 			int interval = plugin.getPollingInterval();
-			if (randomiseNext) interval = randomise(interval);
+			if (randomiseNext)
+				interval = (int) (interval * random.nextDouble());
 			schedule(plugin, interval, false);
 			poll(plugin);
 		}
diff --git a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java
index 9b354427a240b81f05bb54aadade681ccdf3727b..541b8ad5ff4b9cc772f0d262cae36d23f6b8cd4e 100644
--- a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java
+++ b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java
@@ -13,8 +13,8 @@ public class LanTcpPluginFactory implements DuplexPluginFactory {
 
 	private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
 	private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
-	private static final int MIN_POLLING_INTERVAL = 2 * 60 * 1000; // 2 minutes
-	private static final int MAX_POLLING_INTERVAL = 60 * 60 * 1000; // 1 hour
+	private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
+	private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
 	private static final double BACKOFF_BASE = 1.2;
 
 	private final Executor ioExecutor;
@@ -26,14 +26,17 @@ public class LanTcpPluginFactory implements DuplexPluginFactory {
 		this.backoffFactory = backoffFactory;
 	}
 
+	@Override
 	public TransportId getId() {
 		return LanTcpPlugin.ID;
 	}
 
+	@Override
 	public int getMaxLatency() {
 		return MAX_LATENCY;
 	}
 
+	@Override
 	public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
 		Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
 				MAX_POLLING_INTERVAL, BACKOFF_BASE);
diff --git a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java
index 44fdf5edfdf1ffe9b7b4c60c04678f6002dd6d4f..b5e2823ca7ab1e3959ff6e4952d847c08ddeaeb2 100644
--- a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java
+++ b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java
@@ -14,8 +14,8 @@ public class WanTcpPluginFactory implements DuplexPluginFactory {
 
 	private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
 	private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
-	private static final int MIN_POLLING_INTERVAL = 2 * 60 * 1000; // 2 minutes
-	private static final int MAX_POLLING_INTERVAL = 60 * 60 * 1000; // 1 hour
+	private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
+	private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
 	private static final double BACKOFF_BASE = 1.2;
 
 	private final Executor ioExecutor;
@@ -29,14 +29,17 @@ public class WanTcpPluginFactory implements DuplexPluginFactory {
 		this.shutdownManager = shutdownManager;
 	}
 
+	@Override
 	public TransportId getId() {
 		return WanTcpPlugin.ID;
 	}
 
+	@Override
 	public int getMaxLatency() {
 		return MAX_LATENCY;
 	}
 
+	@Override
 	public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
 		Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
 				MAX_POLLING_INTERVAL, BACKOFF_BASE);
diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java
index d4165bc410fbbe3ba5f6a1ff71e55a388bf8945d..1fd6648b3ba134ee6579a9476783c4fc12a357b0 100644
--- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java
+++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java
@@ -13,8 +13,8 @@ import java.util.concurrent.Executor;
 public class BluetoothPluginFactory implements DuplexPluginFactory {
 
 	private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
-	private static final int MIN_POLLING_INTERVAL = 2 * 60 * 1000; // 2 minutes
-	private static final int MAX_POLLING_INTERVAL = 60 * 60 * 1000; // 1 hour
+	private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
+	private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
 	private static final double BACKOFF_BASE = 1.2;
 
 	private final Executor ioExecutor;
@@ -28,14 +28,17 @@ public class BluetoothPluginFactory implements DuplexPluginFactory {
 		this.backoffFactory = backoffFactory;
 	}
 
+	@Override
 	public TransportId getId() {
 		return BluetoothPlugin.ID;
 	}
 
+	@Override
 	public int getMaxLatency() {
 		return MAX_LATENCY;
 	}
 
+	@Override
 	public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
 		Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
 				MAX_POLLING_INTERVAL, BACKOFF_BASE);
diff --git a/briar-tests/src/org/briarproject/plugins/ConnectionRegistryImplTest.java b/briar-tests/src/org/briarproject/plugins/ConnectionRegistryImplTest.java
index 8ea235249bca696de2b2edc2323c5d9ecad2a3cc..b18634e0aa7db117d6ce634cf4d0f411bb5370bd 100644
--- a/briar-tests/src/org/briarproject/plugins/ConnectionRegistryImplTest.java
+++ b/briar-tests/src/org/briarproject/plugins/ConnectionRegistryImplTest.java
@@ -3,6 +3,8 @@ package org.briarproject.plugins;
 import org.briarproject.BriarTestCase;
 import org.briarproject.api.TransportId;
 import org.briarproject.api.contact.ContactId;
+import org.briarproject.api.event.ConnectionClosedEvent;
+import org.briarproject.api.event.ConnectionOpenedEvent;
 import org.briarproject.api.event.ContactConnectedEvent;
 import org.briarproject.api.event.ContactDisconnectedEvent;
 import org.briarproject.api.event.EventBus;
@@ -35,6 +37,10 @@ public class ConnectionRegistryImplTest extends BriarTestCase {
 		Mockery context = new Mockery();
 		final EventBus eventBus = context.mock(EventBus.class);
 		context.checking(new Expectations() {{
+			exactly(5).of(eventBus).broadcast(with(any(
+					ConnectionOpenedEvent.class)));
+			exactly(2).of(eventBus).broadcast(with(any(
+					ConnectionClosedEvent.class)));
 			exactly(3).of(eventBus).broadcast(with(any(
 					ContactConnectedEvent.class)));
 			oneOf(eventBus).broadcast(with(any(
@@ -49,43 +55,46 @@ public class ConnectionRegistryImplTest extends BriarTestCase {
 		assertEquals(Collections.emptyList(),
 				c.getConnectedContacts(transportId1));
 		// Check that a registered connection shows up - this should
-		// broadcast a ContactConnectedEvent
-		c.registerConnection(contactId, transportId);
+		// broadcast a ConnectionOpenedEvent and a ContactConnectedEvent
+		c.registerConnection(contactId, transportId, true);
 		assertEquals(Collections.singletonList(contactId),
 				c.getConnectedContacts(transportId));
 		assertEquals(Collections.emptyList(),
 				c.getConnectedContacts(transportId1));
-		// Register an identical connection - lookup should be unaffected
-		c.registerConnection(contactId, transportId);
+		// Register an identical connection - this should broadcast a
+		// ConnectionOpenedEvent and lookup should be unaffected
+		c.registerConnection(contactId, transportId, true);
 		assertEquals(Collections.singletonList(contactId),
 				c.getConnectedContacts(transportId));
 		assertEquals(Collections.emptyList(),
 				c.getConnectedContacts(transportId1));
-		// Unregister one of the connections - lookup should be unaffected
-		c.unregisterConnection(contactId, transportId);
+		// Unregister one of the connections - this should broadcast a
+		// ConnectionClosedEvent and lookup should be unaffected
+		c.unregisterConnection(contactId, transportId, true);
 		assertEquals(Collections.singletonList(contactId),
 				c.getConnectedContacts(transportId));
 		assertEquals(Collections.emptyList(),
 				c.getConnectedContacts(transportId1));
-		// Unregister the other connection - lookup should be affected -
-		// this should broadcast a ContactDisconnectedEvent
-		c.unregisterConnection(contactId, transportId);
+		// Unregister the other connection - this should broadcast a
+		// ConnectionClosedEvent and a ContactDisconnectedEvent
+		c.unregisterConnection(contactId, transportId, true);
 		assertEquals(Collections.emptyList(),
 				c.getConnectedContacts(transportId));
 		assertEquals(Collections.emptyList(),
 				c.getConnectedContacts(transportId1));
 		// Try to unregister the connection again - exception should be thrown
 		try {
-			c.unregisterConnection(contactId, transportId);
+			c.unregisterConnection(contactId, transportId, true);
 			fail();
 		} catch (IllegalArgumentException expected) {
 			// Expected
 		}
 		// Register both contacts with one transport, one contact with both -
-		// this should broadcast two ContactConnectedEvents
-		c.registerConnection(contactId, transportId);
-		c.registerConnection(contactId1, transportId);
-		c.registerConnection(contactId1, transportId1);
+		// this should broadcast three ConnectionOpenedEvents and two
+		// ContactConnectedEvents
+		c.registerConnection(contactId, transportId, true);
+		c.registerConnection(contactId1, transportId, true);
+		c.registerConnection(contactId1, transportId1, true);
 		Collection<ContactId> connected = c.getConnectedContacts(transportId);
 		assertEquals(2, connected.size());
 		assertTrue(connected.contains(contactId));
diff --git a/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java b/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java
index 6627225c3ddf3417e92b3a2316d4d52baab1e6f9..cd2400c7780c73d92a0fc36f7bf7ce45d9973c0f 100644
--- a/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java
+++ b/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java
@@ -84,9 +84,6 @@ public class PluginManagerImplTest extends BriarTestCase {
 			will(returnValue(simplexPlugin)); // Created
 			oneOf(simplexPlugin).start();
 			will(returnValue(true)); // Started
-			oneOf(simplexPlugin).shouldPoll();
-			will(returnValue(true));
-			oneOf(poller).addPlugin(simplexPlugin);
 			// Second simplex plugin
 			oneOf(simplexFailFactory).getId();
 			will(returnValue(simplexFailId));
@@ -105,8 +102,6 @@ public class PluginManagerImplTest extends BriarTestCase {
 			will(returnValue(duplexPlugin)); // Created
 			oneOf(duplexPlugin).start();
 			will(returnValue(true)); // Started
-			oneOf(duplexPlugin).shouldPoll();
-			will(returnValue(false));
 			// Second duplex plugin
 			oneOf(duplexFailFactory).getId();
 			will(returnValue(duplexFailId));
@@ -193,9 +188,6 @@ public class PluginManagerImplTest extends BriarTestCase {
 			will(returnValue(simplexPlugin)); // Created
 			oneOf(simplexPlugin).start();
 			will(returnValue(true)); // Started
-			oneOf(simplexPlugin).shouldPoll();
-			will(returnValue(true)); // Should poll
-			oneOf(poller).addPlugin(simplexPlugin);
 			// Second simplex plugin
 			oneOf(simplexFactory1).getId();
 			will(returnValue(simplexId1));
@@ -204,8 +196,6 @@ public class PluginManagerImplTest extends BriarTestCase {
 			will(returnValue(simplexPlugin1)); // Created
 			oneOf(simplexPlugin1).start();
 			will(returnValue(true)); // Started
-			oneOf(simplexPlugin1).shouldPoll();
-			will(returnValue(false)); // Should not poll
 			// First duplex plugin
 			oneOf(pluginConfig).getDuplexFactories();
 			will(returnValue(Arrays.asList(duplexFactory, duplexFactory1)));
@@ -216,9 +206,6 @@ public class PluginManagerImplTest extends BriarTestCase {
 			will(returnValue(duplexPlugin)); // Created
 			oneOf(duplexPlugin).start();
 			will(returnValue(true)); // Started
-			oneOf(duplexPlugin).shouldPoll();
-			will(returnValue(true)); // Should poll
-			oneOf(poller).addPlugin(duplexPlugin);
 			// Second duplex plugin
 			oneOf(duplexFactory1).getId();
 			will(returnValue(duplexId1));
@@ -227,8 +214,6 @@ public class PluginManagerImplTest extends BriarTestCase {
 			will(returnValue(duplexPlugin1)); // Created
 			oneOf(duplexPlugin1).start();
 			will(returnValue(true)); // Started
-			oneOf(duplexPlugin1).shouldPoll();
-			will(returnValue(false)); // Should not poll
 			// Start listening for events
 			oneOf(eventBus).addListener(with(any(EventListener.class)));
 			// eventOccurred()