diff --git a/briar-android/res/drawable/transport_bt.xml b/briar-android/res/drawable/transport_bt.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d2217086907b77c459045334224f5eeb31fd1672
--- /dev/null
+++ b/briar-android/res/drawable/transport_bt.xml
@@ -0,0 +1,5 @@
+<vector android:alpha="0.54" android:height="24dp"
+    android:viewportHeight="24.0" android:viewportWidth="24.0"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#FF000000" android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41V22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59V5.83zm1.88,10.46L13,18.17v-3.76l1.88,1.88z"/>
+</vector>
diff --git a/briar-android/res/drawable/transport_lan.xml b/briar-android/res/drawable/transport_lan.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d2cc9189e6f744f29ed6e8ebd4f5bc5053086a31
--- /dev/null
+++ b/briar-android/res/drawable/transport_lan.xml
@@ -0,0 +1,6 @@
+<vector android:alpha="0.54" android:height="24dp"
+    android:viewportHeight="24.0" android:viewportWidth="24.0"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillAlpha=".3" android:fillColor="#FF000000" android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"/>
+    <path android:fillColor="#FF000000" android:pathData="M3.53,10.95l8.46,10.54 0.01,0.01 0.01,-0.01 8.46,-10.54C20.04,10.62 16.81,8 12,8c-4.81,0 -8.04,2.62 -8.47,2.95z"/>
+</vector>
diff --git a/briar-android/res/drawable/transport_tor.xml b/briar-android/res/drawable/transport_tor.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fe462b2f73b95b98df34a0d2169c358b11386e99
--- /dev/null
+++ b/briar-android/res/drawable/transport_tor.xml
@@ -0,0 +1,5 @@
+<vector android:alpha="0.54" android:height="24dp"
+    android:viewportHeight="24.0" android:viewportWidth="24.0"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#FF000000" android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zm6.93,6h-2.95c-0.32,-1.25 -0.78,-2.45 -1.38,-3.56 1.84,0.63 3.37,1.91 4.33,3.56zM12,4.04c0.83,1.2 1.48,2.53 1.91,3.96h-3.82c0.43,-1.43 1.08,-2.76 1.91,-3.96zM4.26,14C4.1,13.36 4,12.69 4,12s0.1,-1.36 0.26,-2h3.38c-0.08,0.66 -0.14,1.32 -0.14,2 0,0.68 0.06,1.34 0.14,2H4.26zm0.82,2h2.95c0.32,1.25 0.78,2.45 1.38,3.56 -1.84,-0.63 -3.37,-1.9 -4.33,-3.56zm2.95,-8H5.08c0.96,-1.66 2.49,-2.93 4.33,-3.56C8.81,5.55 8.35,6.75 8.03,8zM12,19.96c-0.83,-1.2 -1.48,-2.53 -1.91,-3.96h3.82c-0.43,1.43 -1.08,2.76 -1.91,3.96zM14.34,14H9.66c-0.09,-0.66 -0.16,-1.32 -0.16,-2 0,-0.68 0.07,-1.35 0.16,-2h4.68c0.09,0.65 0.16,1.32 0.16,2 0,0.68 -0.07,1.34 -0.16,2zm0.25,5.56c0.6,-1.11 1.06,-2.31 1.38,-3.56h2.95c-0.96,1.65 -2.49,2.93 -4.33,3.56zM16.36,14c0.08,-0.66 0.14,-1.32 0.14,-2 0,-0.68 -0.06,-1.34 -0.14,-2h3.38c0.16,0.64 0.26,1.31 0.26,2s-0.1,1.36 -0.26,2h-3.38z"/>
+</vector>
diff --git a/briar-android/res/layout/list_item_transport.xml b/briar-android/res/layout/list_item_transport.xml
new file mode 100644
index 0000000000000000000000000000000000000000..11c3d5e4de80194d66452b85d838458bb5064f28
--- /dev/null
+++ b/briar-android/res/layout/list_item_transport.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	xmlns:tools="http://schemas.android.com/tools"
+	android:orientation="horizontal"
+	android:layout_width="match_parent"
+	android:layout_height="wrap_content"
+	android:padding="@dimen/margin_small"
+	android:gravity="center_horizontal">
+
+	<ImageView
+		android:id="@+id/imageView"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:padding="@dimen/margin_small"
+		tools:src="@drawable/transport_tor"/>
+
+	<TextView
+		android:id="@+id/textView"
+		android:layout_width="wrap_content"
+		android:layout_height="match_parent"
+		android:gravity="center_vertical"
+		android:padding="@dimen/margin_small"
+		android:textColor="@android:color/tertiary_text_light"
+		tools:text="@string/transport_tor"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/briar-android/res/layout/transports_list.xml b/briar-android/res/layout/transports_list.xml
new file mode 100644
index 0000000000000000000000000000000000000000..02c05e74df5530a427c2651c0aef4e81b7a900e2
--- /dev/null
+++ b/briar-android/res/layout/transports_list.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	android:orientation="vertical"
+	android:layout_width="wrap_content"
+	android:layout_height="wrap_content">
+
+	<View
+		android:layout_width="match_parent"
+		android:layout_height="1px"
+		android:background="@color/horizontal_border"/>
+
+	<GridView
+		android:id="@+id/transportsView"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:padding="@dimen/margin_medium"
+		android:numColumns="3"/>
+
+</LinearLayout>
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 0ce4e1c57ab4cb95b3fb705a932991a5460d5811..bdcf261047ef4d5f6e1fbf25bbda4965a69f7a2d 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -116,6 +116,10 @@
     <string name="online">Online</string>
     <string name="offline">Offline</string>
     <string name="send">Send</string>
+    <string name="data_transports">Data Transports</string>
+    <string name="transport_tor">Internet</string>
+    <string name="transport_bt">Bluetooth</string>
+    <string name="transport_lan">Wi-Fi</string>
 
     <!-- Dialogs -->
     <string name="dialog_title_lost_password">Lost password</string>
diff --git a/briar-android/src/org/briarproject/android/DashboardActivity.java b/briar-android/src/org/briarproject/android/DashboardActivity.java
index fc9d05b881d54ce114b5e25bcbd2ccdac9689272..6e08cd217088694d4a43fed85eef12ea2d807b6a 100644
--- a/briar-android/src/org/briarproject/android/DashboardActivity.java
+++ b/briar-android/src/org/briarproject/android/DashboardActivity.java
@@ -1,26 +1,38 @@
 package org.briarproject.android;
 
+import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
 import android.os.Bundle;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
 import android.widget.Button;
 import android.widget.GridView;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.ProgressBar;
+import android.widget.TextView;
 
 import org.briarproject.R;
 import org.briarproject.android.contact.ContactListActivity;
 import org.briarproject.android.forum.ForumListActivity;
 import org.briarproject.android.util.LayoutUtils;
 import org.briarproject.api.LocalAuthor;
+import org.briarproject.api.TransportId;
 import org.briarproject.api.android.ReferenceManager;
 import org.briarproject.api.db.DatabaseComponent;
 import org.briarproject.api.db.DbException;
+import org.briarproject.api.event.Event;
+import org.briarproject.api.event.EventBus;
+import org.briarproject.api.event.EventListener;
+import org.briarproject.api.event.TransportDisabledEvent;
+import org.briarproject.api.event.TransportEnabledEvent;
+import org.briarproject.api.plugins.Plugin;
+import org.briarproject.api.plugins.PluginManager;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -30,19 +42,25 @@ import javax.inject.Inject;
 
 import static android.view.Gravity.CENTER;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
 import static org.briarproject.android.util.CommonLayoutParams.MATCH_MATCH;
 
-public class DashboardActivity extends BriarActivity {
+public class DashboardActivity extends BriarActivity implements EventListener {
 
 	private static final Logger LOG =
 			Logger.getLogger(DashboardActivity.class.getName());
 
+	private List<Transport> transports;
+	private BaseAdapter transportsAdapter;
+
 	@Inject private ReferenceManager referenceManager;
+	@Inject private PluginManager pluginManager;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject private volatile DatabaseComponent db;
+	@Inject private volatile EventBus eventBus;
 
 	@Override
 	public void onCreate(Bundle state) {
@@ -50,12 +68,43 @@ public class DashboardActivity extends BriarActivity {
 		handleIntent(getIntent());
 	}
 
+	@Override
+	public void onResume() {
+		super.onResume();
+
+		eventBus.addListener(this);
+	}
+
+	@Override
+	public void onPause() {
+		super.onPause();
+
+		eventBus.removeListener(this);
+	}
+
 	@Override
 	public void onNewIntent(Intent i) {
 		super.onNewIntent(i);
 		handleIntent(i);
 	}
 
+	@Override
+	public void eventOccurred(Event e) {
+		if (e instanceof TransportEnabledEvent) {
+			TransportId id = ((TransportEnabledEvent) e).getTransportId();
+			if (LOG.isLoggable(INFO)) {
+				LOG.info("TransportEnabledEvent: " + id.getString());
+			}
+			setTransport(id, true);
+		} else if (e instanceof TransportDisabledEvent) {
+			TransportId id = ((TransportDisabledEvent) e).getTransportId();
+			if (LOG.isLoggable(INFO)) {
+				LOG.info("TransportDisabledEvent: " + id.getString());
+			}
+			setTransport(id, false);
+		}
+	}
+
 	private void handleIntent(Intent i) {
 		boolean failed = i.getBooleanExtra("briar.STARTUP_FAILED", false);
 		long handle = i.getLongExtra("briar.LOCAL_AUTHOR_HANDLE", -1);
@@ -144,8 +193,14 @@ public class DashboardActivity extends BriarActivity {
 
 		int pad = LayoutUtils.getPadding(this);
 
+		LinearLayout layout = new LinearLayout(this);
+		layout.setLayoutParams(MATCH_MATCH);
+		layout.setOrientation(LinearLayout.VERTICAL);
+
 		GridView grid = new GridView(this);
-		grid.setLayoutParams(matchMatch);
+		LinearLayout.LayoutParams params =
+				new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT, 1f);
+		grid.setLayoutParams(params);
 		grid.setGravity(CENTER);
 		grid.setPadding(pad, pad, pad, pad);
 		Resources res = getResources();
@@ -170,7 +225,21 @@ public class DashboardActivity extends BriarActivity {
 				return buttons.get(position);
 			}
 		});
-		setContentView(grid);
+		layout.addView(grid);
+
+		// inflate transports layout
+		LayoutInflater inflater = (LayoutInflater) getSystemService
+				(Context.LAYOUT_INFLATER_SERVICE);
+		ViewGroup transportsLayout = (ViewGroup) inflater.
+				inflate(R.layout.transports_list, layout);
+
+		initializeTransports();
+
+		GridView transportsView = (GridView) transportsLayout.findViewById(
+				R.id.transportsView);
+		transportsView.setAdapter(transportsAdapter);
+
+		setContentView(layout);
 	}
 
 	private void showSpinner() {
@@ -206,4 +275,105 @@ public class DashboardActivity extends BriarActivity {
 			}
 		});
 	}
+
+	private void initializeTransports() {
+		transports = new ArrayList<Transport>(3);
+
+		Transport tor = new Transport();
+		tor.id = new TransportId("tor");
+		Plugin torPlugin = pluginManager.getPlugin(tor.id);
+		if (torPlugin == null) tor.enabled = false;
+		else tor.enabled = torPlugin.isRunning();
+		tor.iconId = R.drawable.transport_tor;
+		tor.textId = R.string.transport_tor;
+		transports.add(tor);
+
+		Transport bt = new Transport();
+		bt.id = new TransportId("bt");
+		Plugin btPlugin = pluginManager.getPlugin(bt.id);
+		if (btPlugin == null) bt.enabled = false;
+		else bt.enabled = btPlugin.isRunning();
+		bt.iconId = R.drawable.transport_bt;
+		bt.textId = R.string.transport_bt;
+		transports.add(bt);
+
+		Transport lan = new Transport();
+		lan.id = new TransportId("lan");
+		Plugin lanPlugin = pluginManager.getPlugin(lan.id);
+		if (lanPlugin == null) lan.enabled = false;
+		else lan.enabled = lanPlugin.isRunning();
+		lan.iconId = R.drawable.transport_lan;
+		lan.textId = R.string.transport_lan;
+		transports.add(lan);
+
+		transportsAdapter = new BaseAdapter() {
+			@Override
+			public int getCount() {
+				return transports.size();
+			}
+
+			@Override
+			public Transport getItem(int position) {
+				return transports.get(position);
+			}
+
+			@Override
+			public long getItemId(int position) {
+				return 0;
+			}
+
+			@Override
+			public View getView(int position, View convertView,
+					ViewGroup parent) {
+				LayoutInflater inflater = (LayoutInflater) getSystemService(
+						Context.LAYOUT_INFLATER_SERVICE);
+				ViewGroup view = (ViewGroup) inflater
+						.inflate(R.layout.list_item_transport, parent, false);
+
+				Transport t = getItem(position);
+				Resources r = getResources();
+
+				int c;
+				if (t.enabled) {
+					c = r.getColor(R.color.briar_green_light);
+				} else {
+					c = r.getColor(android.R.color.tertiary_text_light);
+				}
+
+				ImageView icon = (ImageView) view.findViewById(R.id.imageView);
+				icon.setImageDrawable(r.getDrawable(t.iconId));
+				icon.setColorFilter(c);
+
+				TextView text = (TextView) view.findViewById(R.id.textView);
+				text.setText(getString(t.textId));
+				text.setTextColor(c);
+
+				return view;
+			}
+		};
+	}
+
+	private void setTransport(final TransportId id, final boolean enabled) {
+		runOnUiThread(new Runnable() {
+			public void run() {
+				if (transports == null || transportsAdapter == null) return;
+
+				for (Transport t : transports) {
+					if (t.id.equals(id)) {
+						t.enabled = enabled;
+						break;
+					}
+				}
+
+				transportsAdapter.notifyDataSetChanged();
+			}
+		});
+	}
+
+	private static class Transport {
+		TransportId id;
+		boolean enabled;
+		int iconId;
+		int textId;
+	}
 }
diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java
index 4191e356171c657b0955d2ee53f1d0a3c81e77a7..06dfd1dc9cdba8053203aa8461af38f3f3c67de2 100644
--- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java
+++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java
@@ -172,7 +172,7 @@ class DroidtoothPlugin implements DuplexPlugin {
 				}
 				LOG.info("Socket bound");
 				socket = ss;
-				callback.pollNow();
+				callback.transportEnabled();
 				acceptContactConnections();
 			}
 		});
@@ -196,6 +196,8 @@ class DroidtoothPlugin implements DuplexPlugin {
 			if (ss != null) ss.close();
 		} catch (IOException e) {
 			if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+		} finally {
+			callback.transportDisabled();
 		}
 	}
 
diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
index ffd6919dbfc4e15542fca4dd63bfda7fb81d7a8e..ebd954dfa559bb90f85b1dda16cb7984e3201dc2 100644
--- a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
+++ b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
@@ -391,6 +391,8 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 			if (ss != null) ss.close();
 		} catch (IOException e) {
 			if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+		} finally {
+			callback.transportDisabled();
 		}
 	}
 
@@ -459,7 +461,10 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 	private void enableNetwork(boolean enable) throws IOException {
 		if (!running) return;
 		if (LOG.isLoggable(INFO)) LOG.info("Enabling network: " + enable);
-		if (!enable) circuitBuilt.set(false);
+		if (!enable) {
+			circuitBuilt.set(false);
+			callback.transportDisabled();
+		}
 		networkEnabled = enable;
 		controlConnection.setConf("DisableNetwork", enable ? "0" : "1");
 	}
@@ -549,7 +554,7 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 	public void circuitStatus(String status, String id, String path) {
 		if (status.equals("BUILT") && !circuitBuilt.getAndSet(true)) {
 			LOG.info("First circuit built");
-			if (isRunning()) callback.pollNow();
+			if (isRunning()) callback.transportEnabled();
 		}
 	}
 
@@ -567,7 +572,7 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 		if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg);
 		if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
 			bootstrapped = true;
-			if (isRunning()) callback.pollNow();
+			if (isRunning()) callback.transportEnabled();
 		}
 	}
 
diff --git a/briar-api/src/org/briarproject/api/event/TransportDisabledEvent.java b/briar-api/src/org/briarproject/api/event/TransportDisabledEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..1efb575fdfc576f0527982d6b53dba69c0fefb23
--- /dev/null
+++ b/briar-api/src/org/briarproject/api/event/TransportDisabledEvent.java
@@ -0,0 +1,17 @@
+package org.briarproject.api.event;
+
+import org.briarproject.api.TransportId;
+
+/** An event that is broadcast when a transport is disabled. */
+public class TransportDisabledEvent extends Event {
+
+	private final TransportId transportId;
+
+	public TransportDisabledEvent(TransportId transportId) {
+		this.transportId = transportId;
+	}
+
+	public TransportId getTransportId() {
+		return transportId;
+	}
+}
diff --git a/briar-api/src/org/briarproject/api/event/TransportEnabledEvent.java b/briar-api/src/org/briarproject/api/event/TransportEnabledEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a72d83587250bb21ebe7a90f52365c27330a908
--- /dev/null
+++ b/briar-api/src/org/briarproject/api/event/TransportEnabledEvent.java
@@ -0,0 +1,17 @@
+package org.briarproject.api.event;
+
+import org.briarproject.api.TransportId;
+
+/** An event that is broadcast when a transport is enabled. */
+public class TransportEnabledEvent extends Event {
+
+	private final TransportId transportId;
+
+	public TransportEnabledEvent(TransportId transportId) {
+		this.transportId = transportId;
+	}
+
+	public TransportId getTransportId() {
+		return transportId;
+	}
+}
diff --git a/briar-api/src/org/briarproject/api/plugins/PluginCallback.java b/briar-api/src/org/briarproject/api/plugins/PluginCallback.java
index 3a5890b2d24a1292d2f6269200b52af4c8442dc0..34361a2cab62ae52adb13ac528dc5907659a7d89 100644
--- a/briar-api/src/org/briarproject/api/plugins/PluginCallback.java
+++ b/briar-api/src/org/briarproject/api/plugins/PluginCallback.java
@@ -50,6 +50,9 @@ public interface PluginCallback {
 	 */
 	void showMessage(String... message);
 
-	/** Schedules the plugin to be polled immediately. */
-	void pollNow();
+	/** Signal that the transport got enabled. */
+	void transportEnabled();
+
+	/** Signal that the transport got disabled. */
+	void transportDisabled();
 }
diff --git a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java
index 53448084821c3516bc3116bc377940754a87947f..4742d82513dbccd61014300611dc4c2582f78417 100644
--- a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java
+++ b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java
@@ -6,6 +6,9 @@ import org.briarproject.api.TransportId;
 import org.briarproject.api.TransportProperties;
 import org.briarproject.api.db.DatabaseComponent;
 import org.briarproject.api.db.DbException;
+import org.briarproject.api.event.EventBus;
+import org.briarproject.api.event.TransportDisabledEvent;
+import org.briarproject.api.event.TransportEnabledEvent;
 import org.briarproject.api.lifecycle.IoExecutor;
 import org.briarproject.api.plugins.ConnectionManager;
 import org.briarproject.api.plugins.Plugin;
@@ -48,6 +51,7 @@ class PluginManagerImpl implements PluginManager {
 			Logger.getLogger(PluginManagerImpl.class.getName());
 
 	private final Executor ioExecutor;
+	private final EventBus eventBus;
 	private final SimplexPluginConfig simplexPluginConfig;
 	private final DuplexPluginConfig duplexPluginConfig;
 	private final Clock clock;
@@ -60,12 +64,13 @@ class PluginManagerImpl implements PluginManager {
 	private final List<DuplexPlugin> duplexPlugins;
 
 	@Inject
-	PluginManagerImpl(@IoExecutor Executor ioExecutor,
+	PluginManagerImpl(@IoExecutor Executor ioExecutor, EventBus eventBus,
 			SimplexPluginConfig simplexPluginConfig,
 			DuplexPluginConfig duplexPluginConfig, Clock clock,
 			DatabaseComponent db, Poller poller,
 			ConnectionManager connectionManager, UiCallback uiCallback) {
 		this.ioExecutor = ioExecutor;
+		this.eventBus = eventBus;
 		this.simplexPluginConfig = simplexPluginConfig;
 		this.duplexPluginConfig = duplexPluginConfig;
 		this.clock = clock;
@@ -360,10 +365,16 @@ class PluginManagerImpl implements PluginManager {
 			uiCallback.showMessage(message);
 		}
 
-		public void pollNow() {
+		public void transportEnabled() {
+			eventBus.broadcast(new TransportEnabledEvent(id));
+
 			Plugin p = plugins.get(id);
 			if (p != null) poller.pollNow(p);
 		}
+
+		public void transportDisabled() {
+			eventBus.broadcast(new TransportDisabledEvent(id));
+		}
 	}
 
 	private class SimplexCallback extends PluginCallbackImpl
diff --git a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java
index 369b5a6d28db00912e9ea3e5008fc42e237288c0..48f731464f6bc89043dae23301da637a2aa5a77a 100644
--- a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java
+++ b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java
@@ -106,7 +106,7 @@ abstract class TcpPlugin implements DuplexPlugin {
 				SocketAddress local = ss.getLocalSocketAddress();
 				setLocalSocketAddress((InetSocketAddress) local);
 				if (LOG.isLoggable(INFO)) LOG.info("Listening on " + local);
-				callback.pollNow();
+				callback.transportEnabled();
 				acceptContactConnections();
 			}
 		});
@@ -117,6 +117,8 @@ abstract class TcpPlugin implements DuplexPlugin {
 			if (ss != null) ss.close();
 		} catch (IOException e) {
 			if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+		} finally {
+			callback.transportDisabled();
 		}
 	}
 
diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java
index 3db1dfebfa8f6bb7170277c8feb1009973a80483..792db1398dc778457c0cd3f85b7383b8d5c6c086 100644
--- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java
+++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java
@@ -117,7 +117,7 @@ class BluetoothPlugin implements DuplexPlugin {
 					return;
 				}
 				socket = ss;
-				callback.pollNow();
+				callback.transportEnabled();
 				acceptContactConnections(ss);
 			}
 		});
@@ -145,6 +145,8 @@ class BluetoothPlugin implements DuplexPlugin {
 			if (ss != null) ss.close();
 		} catch (IOException e) {
 			if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+		} finally {
+			callback.transportDisabled();
 		}
 	}
 
diff --git a/briar-tests/src/org/briarproject/plugins/DuplexClientTest.java b/briar-tests/src/org/briarproject/plugins/DuplexClientTest.java
index e36624a5dd6d86bb54d28956c11dac262663883f..a32cf9683bc5e105250965cab9f5fcd7ba8931e1 100644
--- a/briar-tests/src/org/briarproject/plugins/DuplexClientTest.java
+++ b/briar-tests/src/org/briarproject/plugins/DuplexClientTest.java
@@ -100,11 +100,13 @@ public abstract class DuplexClientTest extends DuplexTest {
 
 		public void showMessage(String... message) {}
 
-		public void pollNow() {}
-
 		public void incomingConnectionCreated(DuplexTransportConnection d) {}
 
 		public void outgoingConnectionCreated(ContactId contactId,
 				DuplexTransportConnection d) {}
+
+		public void transportEnabled() {}
+
+		public void transportDisabled() {}
 	}
 }
diff --git a/briar-tests/src/org/briarproject/plugins/DuplexServerTest.java b/briar-tests/src/org/briarproject/plugins/DuplexServerTest.java
index ba73b0ace3e979c2bbf65e91d022de2e5d4c260b..daf3c47407a19f83787ab22ba85aeb08e6fbf50e 100644
--- a/briar-tests/src/org/briarproject/plugins/DuplexServerTest.java
+++ b/briar-tests/src/org/briarproject/plugins/DuplexServerTest.java
@@ -99,8 +99,6 @@ public abstract class DuplexServerTest extends DuplexTest {
 
 		public void showMessage(String... message) {}
 
-		public void pollNow() {}
-
 		public void incomingConnectionCreated(DuplexTransportConnection d) {
 			System.out.println("Connection received");
 			sendChallengeReceiveResponse(d);
@@ -109,5 +107,9 @@ public abstract class DuplexServerTest extends DuplexTest {
 
 		public void outgoingConnectionCreated(ContactId c,
 				DuplexTransportConnection d) {}
+
+		public void transportEnabled() {}
+
+		public void transportDisabled() {}
 	}
 }
diff --git a/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java b/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java
index 5493a0178bd8dd886a91f0e8a1348164f553a1c8..1394a998b4a3f4f85d3993b3ca4d6e034d93ff2c 100644
--- a/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java
+++ b/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java
@@ -3,6 +3,8 @@ package org.briarproject.plugins;
 import org.briarproject.BriarTestCase;
 import org.briarproject.api.TransportId;
 import org.briarproject.api.db.DatabaseComponent;
+import org.briarproject.api.event.EventBus;
+import org.briarproject.api.lifecycle.IoExecutor;
 import org.briarproject.api.plugins.ConnectionManager;
 import org.briarproject.api.plugins.duplex.DuplexPlugin;
 import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
@@ -32,6 +34,7 @@ public class PluginManagerImplTest extends BriarTestCase {
 		Clock clock = new SystemClock();
 		Mockery context = new Mockery();
 		final Executor ioExecutor = Executors.newCachedThreadPool();
+		final EventBus eventBus = context.mock(EventBus.class);
 		final SimplexPluginConfig simplexPluginConfig =
 				context.mock(SimplexPluginConfig.class);
 		final DuplexPluginConfig duplexPluginConfig =
@@ -121,9 +124,10 @@ public class PluginManagerImplTest extends BriarTestCase {
 			oneOf(simplexPlugin).stop();
 			oneOf(duplexPlugin).stop();
 		}});
-		PluginManagerImpl p = new PluginManagerImpl(ioExecutor,
+		PluginManagerImpl p = new PluginManagerImpl(ioExecutor, eventBus,
 				simplexPluginConfig, duplexPluginConfig, clock, db, poller,
 				dispatcher, uiCallback);
+
 		// Two plugins should be started and stopped
 		assertTrue(p.start());
 		assertTrue(p.stop());
diff --git a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java
index b929c8f528c19f9b13e01d025a1cddf13821833d..575b8f136e3c048a73998be5f64f9ae3274b86ff 100644
--- a/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java
+++ b/briar-tests/src/org/briarproject/plugins/tcp/LanTcpPluginTest.java
@@ -205,13 +205,15 @@ public class LanTcpPluginTest extends BriarTestCase {
 
 		public void showMessage(String... message) {}
 
-		public void pollNow() {}
-
 		public void incomingConnectionCreated(DuplexTransportConnection d) {
 			connectionsLatch.countDown();
 		}
 
 		public void outgoingConnectionCreated(ContactId c,
 				DuplexTransportConnection d) {}
+
+		public void transportEnabled() {}
+
+		public void transportDisabled() {}
 	}
 }