diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
index 3b8e56cc657b23b6128ba5e71d8b39acb7c94cf2..3abd0feff7800d6c688e43bf796daf793206166a 100644
--- a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
+++ b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
@@ -50,8 +50,6 @@ import java.util.List;
 import java.util.Scanner;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Logger;
 import java.util.regex.Pattern;
 import java.util.zip.ZipInputStream;
@@ -60,15 +58,13 @@ import static android.content.Context.CONNECTIVITY_SERVICE;
 import static android.content.Context.MODE_PRIVATE;
 import static android.content.Context.POWER_SERVICE;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.EXTRA_NO_CONNECTIVITY;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
 
-class TorPlugin implements DuplexPlugin, EventHandler,
-		EventListener {
+class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 
 	static final TransportId ID = new TransportId("tor");
 
@@ -93,18 +89,12 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 	private final DuplexPluginCallback callback;
 	private final String architecture;
 	private final int maxLatency, maxIdleTime, pollingInterval, socketTimeout;
+	private final ConnectionStatus connectionStatus;
 	private final File torDirectory, torFile, geoIpFile, configFile, doneFile;
 	private final File cookieFile, hostnameFile;
-	private final AtomicBoolean circuitBuilt;
-	private final AtomicInteger descriptorsPublished;
 	private final PowerManager.WakeLock wakeLock;
 
-	private volatile boolean running = false, networkEnabled = false;
-	private volatile boolean bootstrapped = false;
-	private volatile boolean connectedToWifi = false;
-	private volatile boolean online = false;
-	private volatile long descriptorsPublishedTime = Long.MAX_VALUE;
-
+	private volatile boolean running = false;
 	private volatile ServerSocket socket = null;
 	private volatile Socket controlSocket = null;
 	private volatile TorControlConnection controlConnection = null;
@@ -127,6 +117,7 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 		if (maxIdleTime > Integer.MAX_VALUE / 2)
 			socketTimeout = Integer.MAX_VALUE;
 		else socketTimeout = maxIdleTime * 2;
+		connectionStatus = new ConnectionStatus(pollingInterval);
 		torDirectory = appContext.getDir("tor", MODE_PRIVATE);
 		torFile = new File(torDirectory, "tor");
 		geoIpFile = new File(torDirectory, "geoip");
@@ -134,8 +125,6 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 		doneFile = new File(torDirectory, "done");
 		cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
 		hostnameFile = new File(torDirectory, "hs/hostname");
-		circuitBuilt = new AtomicBoolean(false);
-		descriptorsPublished = new AtomicInteger(0);
 		Object o = appContext.getSystemService(POWER_SERVICE);
 		PowerManager pm = (PowerManager) o;
 		wakeLock = pm.newWakeLock(PARTIAL_WAKE_LOCK, "TorPlugin");
@@ -237,7 +226,7 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 			String phase = controlConnection.getInfo("status/bootstrap-phase");
 			if (phase != null && phase.contains("PROGRESS=100")) {
 				LOG.info("Tor has already bootstrapped");
-				bootstrapped = true;
+				connectionStatus.setBootstrapped();
 				sendCrashReports();
 			}
 		}
@@ -495,13 +484,8 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 
 	private void enableNetwork(boolean enable) throws IOException {
 		if (!running) return;
-		if (networkEnabled == enable) return;
-		if (LOG.isLoggable(INFO)) LOG.info("Enabling network: " + enable);
 		if (enable) wakeLock.acquire();
-		circuitBuilt.set(false);
-		descriptorsPublished.set(0);
-		descriptorsPublishedTime = Long.MAX_VALUE;
-		networkEnabled = enable;
+		connectionStatus.enableNetwork(enable);
 		controlConnection.setConf("DisableNetwork", enable ? "0" : "1");
 		if (!enable) {
 			callback.transportDisabled();
@@ -532,7 +516,7 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 	}
 
 	public boolean isRunning() {
-		return running && networkEnabled && bootstrapped && circuitBuilt.get();
+		return running && connectionStatus.isConnected();
 	}
 
 	public boolean shouldPoll() {
@@ -545,16 +529,13 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 
 	public void poll(Collection<ContactId> connected) {
 		if (!isRunning()) return;
-		if (descriptorsPublished.get() >= MIN_DESCRIPTORS_PUBLISHED) {
-			long now = clock.currentTimeMillis();
-			if (now - descriptorsPublishedTime >= 2 * pollingInterval) {
-				LOG.info("Hidden service descriptor published, not polling");
-				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");
 		}
-		// TODO: Pass properties to connectAndCallBack()
-		for (ContactId c : callback.getRemoteProperties().keySet())
-			if (!connected.contains(c)) connectAndCallBack(c);
 	}
 
 	private void connectAndCallBack(final ContactId c) {
@@ -616,7 +597,7 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 	}
 
 	public void circuitStatus(String status, String id, String path) {
-		if (status.equals("BUILT") && !circuitBuilt.getAndSet(true)) {
+		if (status.equals("BUILT") && connectionStatus.setCircuitBuilt()) {
 			LOG.info("First circuit built");
 			if (isRunning()) callback.transportEnabled();
 		}
@@ -638,20 +619,15 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 	public void message(String severity, String msg) {
 		if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg);
 		if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
-			bootstrapped = true;
+			connectionStatus.setBootstrapped();
 			sendCrashReports();
 			if (isRunning()) callback.transportEnabled();
 		}
 	}
 
 	public void unrecognized(String type, String msg) {
-		if (type.equals("HS_DESC") && msg.startsWith("UPLOADED")) {
-			int descriptors = descriptorsPublished.incrementAndGet();
-			if (descriptors == MIN_DESCRIPTORS_PUBLISHED) {
-				LOG.info("Hidden service descriptor published");
-				descriptorsPublishedTime = clock.currentTimeMillis();
-			}
-		}
+		if (type.equals("HS_DESC") && msg.startsWith("UPLOADED"))
+			connectionStatus.descriptorPublished(clock.currentTimeMillis());
 	}
 
 	private static class WriteObserver extends FileObserver {
@@ -673,7 +649,7 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 	public void eventOccurred(Event e) {
 		if (e instanceof SettingsUpdatedEvent) {
 			if (((SettingsUpdatedEvent) e).getNamespace().equals("tor")) {
-				// Wifi setting may have been updated
+				LOG.info("Tor settings updated");
 				updateConnectionStatus();
 			}
 		}
@@ -684,17 +660,23 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 			public void run() {
 				if (!running) return;
 
+				Object o = appContext.getSystemService(CONNECTIVITY_SERVICE);
+				ConnectivityManager cm = (ConnectivityManager) o;
+				NetworkInfo net = cm.getActiveNetworkInfo();
+				boolean online = net != null  && net.isConnected();
+				boolean wifi = online && net.getType() == TYPE_WIFI;
 				String country = locationUtils.getCurrentCountry();
-				if (LOG.isLoggable(INFO)) {
-					LOG.info("Online: " + online);
-					if ("".equals(country)) LOG.info("Country code unknown");
-					else LOG.info("Country code: " + country);
-				}
 				boolean blocked = TorNetworkMetadata.isTorProbablyBlocked(
 						country);
 				Settings s = callback.getSettings();
 				boolean useMobileData = s.getBoolean("torOverMobile", true);
 
+				if (LOG.isLoggable(INFO)) {
+					LOG.info("Online: " + online + ", wifi: " + wifi);
+					if ("".equals(country)) LOG.info("Country code unknown");
+					else LOG.info("Country code: " + country);
+				}
+
 				try {
 					if (!online) {
 						LOG.info("Disabling network, device is offline");
@@ -702,10 +684,11 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 					} else if (blocked) {
 						LOG.info("Disabling network, country is blocked");
 						enableNetwork(false);
-					} else if (!useMobileData & !connectedToWifi) {
+					} else if (!wifi && !useMobileData) {
 						LOG.info("Disabling network due to data setting");
 						enableNetwork(false);
 					} else {
+						LOG.info("Enabling network");
 						enableNetwork(true);
 					}
 				} catch (IOException e) {
@@ -723,16 +706,55 @@ class TorPlugin implements DuplexPlugin, EventHandler,
 			if (!running) return;
 			if (CONNECTIVITY_ACTION.equals(i.getAction())) {
 				LOG.info("Detected connectivity change");
-				online = !i.getBooleanExtra(EXTRA_NO_CONNECTIVITY, false);
-				// Some devices fail to set EXTRA_NO_CONNECTIVITY, double check
-				Object o = ctx.getSystemService(CONNECTIVITY_SERVICE);
-				ConnectivityManager cm = (ConnectivityManager) o;
-				NetworkInfo net = cm.getActiveNetworkInfo();
-				if (net == null || !net.isConnected()) online = false;
-				connectedToWifi = (net != null && net.getType() == TYPE_WIFI
-						&& net.isConnected());
 				updateConnectionStatus();
 			}
 		}
 	}
+
+	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;
+		}
+
+		private synchronized boolean setCircuitBuilt() {
+			boolean firstCircuit = !circuitBuilt;
+			circuitBuilt = true;
+			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;
+		}
+	}
 }