From fd6bf42ea4155b570345def11f958bea0e85da36 Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Wed, 10 Jan 2018 16:51:06 +0000
Subject: [PATCH] Don't make Bluetooth connections when configured not to.

---
 .../bluetooth/AndroidBluetoothPlugin.java     | 81 ++++++++-----------
 .../plugin/bluetooth/BluetoothPlugin.java     | 78 +++++++++++++-----
 .../bramble/plugin/DesktopPluginModule.java   |  5 +-
 .../plugin/bluetooth/JavaBluetoothPlugin.java |  7 +-
 .../bluetooth/JavaBluetoothPluginFactory.java | 12 ++-
 .../android/settings/SettingsFragment.java    |  8 --
 6 files changed, 109 insertions(+), 82 deletions(-)

diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPlugin.java
index 8bbfe971d2..6adbd5adb8 100644
--- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPlugin.java
+++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPlugin.java
@@ -9,15 +9,12 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 
-import org.briarproject.bramble.api.event.Event;
-import org.briarproject.bramble.api.event.EventListener;
 import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
 import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
 import org.briarproject.bramble.api.plugin.Backoff;
+import org.briarproject.bramble.api.plugin.PluginException;
 import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
 import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
-import org.briarproject.bramble.api.plugin.event.DisableBluetoothEvent;
-import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
 import org.briarproject.bramble.api.system.AndroidExecutor;
 import org.briarproject.bramble.util.AndroidUtils;
 
@@ -44,8 +41,7 @@ import static java.util.logging.Level.WARNING;
 
 @MethodsNotNullByDefault
 @ParametersNotNullByDefault
-class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket>
-		implements EventListener {
+class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
 
 	private static final Logger LOG =
 			Logger.getLogger(AndroidBluetoothPlugin.class.getName());
@@ -67,6 +63,23 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket>
 		this.appContext = appContext;
 	}
 
+	@Override
+	public void start() throws PluginException {
+		super.start();
+		// Listen for changes to the Bluetooth state
+		IntentFilter filter = new IntentFilter();
+		filter.addAction(ACTION_STATE_CHANGED);
+		filter.addAction(ACTION_SCAN_MODE_CHANGED);
+		receiver = new BluetoothStateReceiver();
+		appContext.registerReceiver(receiver, filter);
+	}
+
+	@Override
+	public void stop() {
+		super.stop();
+		if (receiver != null) appContext.unregisterReceiver(receiver);
+	}
+
 	@Override
 	void initialiseAdapter() throws IOException {
 		// BluetoothAdapter.getDefaultAdapter() must be called on a thread
@@ -77,21 +90,13 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket>
 		} catch (InterruptedException | ExecutionException e) {
 			throw new IOException(e);
 		}
-		if (adapter == null) {
-			LOG.info("Bluetooth is not supported");
-			throw new IOException();
-		}
-		// Listen for changes to the Bluetooth state
-		IntentFilter filter = new IntentFilter();
-		filter.addAction(ACTION_STATE_CHANGED);
-		filter.addAction(ACTION_SCAN_MODE_CHANGED);
-		receiver = new BluetoothStateReceiver();
-		appContext.registerReceiver(receiver, filter);
+		if (adapter == null)
+			throw new IOException("Bluetooth is not supported");
 	}
 
 	@Override
 	boolean isAdapterEnabled() {
-		return adapter.isEnabled();
+		return adapter != null && adapter.isEnabled();
 	}
 
 	@Override
@@ -107,24 +112,14 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket>
 	}
 
 	@Override
-	public void stop() {
-		super.stop();
-		if (receiver != null) appContext.unregisterReceiver(receiver);
-		disableAdapter();
-	}
-
-	private void disableAdapter() {
-		if (adapter != null && adapter.isEnabled() && wasEnabledByUs) {
+	void disableAdapterIfEnabledByUs() {
+		if (isAdapterEnabled() && wasEnabledByUs) {
 			if (adapter.disable()) LOG.info("Disabling Bluetooth");
 			else LOG.info("Could not disable Bluetooth");
+			wasEnabledByUs = false;
 		}
 	}
 
-	@Override
-	public boolean isRunning() {
-		return super.isRunning() && adapter != null && adapter.isEnabled();
-	}
-
 	@Override
 	@Nullable
 	String getBluetoothAddress() {
@@ -186,30 +181,18 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket>
 		}
 	}
 
-	@Override
-	public void eventOccurred(Event e) {
-		if (e instanceof EnableBluetoothEvent) {
-			enableAdapterAsync();
-		} else if (e instanceof DisableBluetoothEvent) {
-			disableAdapterAsync();
-		}
-	}
-
-	private void enableAdapterAsync() {
-		ioExecutor.execute(this::enableAdapter);
-	}
-
-	private void disableAdapterAsync() {
-		ioExecutor.execute(this::disableAdapter);
-	}
-
 	private class BluetoothStateReceiver extends BroadcastReceiver {
 
 		@Override
 		public void onReceive(Context ctx, Intent intent) {
 			int state = intent.getIntExtra(EXTRA_STATE, 0);
-			if (state == STATE_ON) onAdapterEnabled();
-			else if (state == STATE_OFF) onAdapterDisabled();
+			if (state == STATE_ON) {
+				ioExecutor.execute(
+						AndroidBluetoothPlugin.this::onAdapterEnabled);
+			} else if (state == STATE_OFF) {
+				ioExecutor.execute(
+						AndroidBluetoothPlugin.this::onAdapterDisabled);
+			}
 			int scanMode = intent.getIntExtra(EXTRA_SCAN_MODE, 0);
 			if (scanMode == SCAN_MODE_NONE) {
 				LOG.info("Scan mode: None");
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java
index 4da5916f4a..bafd0649fc 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java
@@ -3,6 +3,8 @@ package org.briarproject.bramble.plugin.bluetooth;
 import org.briarproject.bramble.api.FormatException;
 import org.briarproject.bramble.api.contact.ContactId;
 import org.briarproject.bramble.api.data.BdfList;
+import org.briarproject.bramble.api.event.Event;
+import org.briarproject.bramble.api.event.EventListener;
 import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
 import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
 import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
@@ -13,7 +15,10 @@ import org.briarproject.bramble.api.plugin.TransportId;
 import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
 import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
 import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
+import org.briarproject.bramble.api.plugin.event.DisableBluetoothEvent;
+import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
 import org.briarproject.bramble.api.properties.TransportProperties;
+import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
 import org.briarproject.bramble.util.StringUtils;
 
 import java.io.IOException;
@@ -41,7 +46,7 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
 
 @MethodsNotNullByDefault
 @ParametersNotNullByDefault
-abstract class BluetoothPlugin<SS> implements DuplexPlugin {
+abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
 
 	private static final Logger LOG =
 			Logger.getLogger(BluetoothPlugin.class.getName());
@@ -54,7 +59,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
 	private final int maxLatency;
 	private final AtomicBoolean used = new AtomicBoolean(false);
 
-	private volatile boolean running = false;
+	private volatile boolean running = false, contactConnections = false;
 	private volatile SS socket = null;
 
 	abstract void initialiseAdapter() throws IOException;
@@ -63,6 +68,8 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
 
 	abstract void enableAdapter();
 
+	abstract void disableAdapterIfEnabledByUs();
+
 	@Nullable
 	abstract String getBluetoothAddress();
 
@@ -89,7 +96,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
 
 	void onAdapterEnabled() {
 		LOG.info("Bluetooth enabled");
-		bind();
+		if (shouldAllowContactConnections()) bind();
 	}
 
 	void onAdapterDisabled() {
@@ -123,22 +130,25 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
 			throw new PluginException(e);
 		}
 		running = true;
-		// If Bluetooth is enabled, bind a socket
-		if (isAdapterEnabled()) {
-			bind();
-		} else {
-			// Enable Bluetooth if settings allow
-			if (callback.getSettings().getBoolean(PREF_BT_ENABLE, false)) {
-				enableAdapter();
-			} else {
-				LOG.info("Not enabling Bluetooth");
-			}
+		loadSettings();
+		if (shouldAllowContactConnections()) {
+			if (isAdapterEnabled()) bind();
+			else enableAdapter();
 		}
 	}
 
+	private void loadSettings() {
+		contactConnections =
+				callback.getSettings().getBoolean(PREF_BT_ENABLE, false);
+	}
+
+	private boolean shouldAllowContactConnections() {
+		return contactConnections;
+	}
+
 	private void bind() {
 		ioExecutor.execute(() -> {
-			if (!isRunning()) return;
+			if (!isRunning() || !shouldAllowContactConnections()) return;
 			String address = getBluetoothAddress();
 			if (LOG.isLoggable(INFO))
 				LOG.info("Local address " + scrubMacAddress(address));
@@ -156,7 +166,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
 				if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
 				return;
 			}
-			if (!isRunning()) {
+			if (!isRunning() || !shouldAllowContactConnections()) {
 				tryToClose(ss);
 				return;
 			}
@@ -201,11 +211,12 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
 		running = false;
 		tryToClose(socket);
 		callback.transportDisabled();
+		disableAdapterIfEnabledByUs();
 	}
 
 	@Override
 	public boolean isRunning() {
-		return running;
+		return running && isAdapterEnabled();
 	}
 
 	@Override
@@ -220,7 +231,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
 
 	@Override
 	public void poll(Collection<ContactId> connected) {
-		if (!isRunning()) return;
+		if (!isRunning() || !shouldAllowContactConnections()) return;
 		backoff.increment();
 		// Try to connect to known devices in parallel
 		Map<ContactId, TransportProperties> remote =
@@ -233,7 +244,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
 			String uuid = e.getValue().get(PROP_UUID);
 			if (StringUtils.isNullOrEmpty(uuid)) continue;
 			ioExecutor.execute(() -> {
-				if (!isRunning()) return;
+				if (!isRunning() || !shouldAllowContactConnections()) return;
 				DuplexTransportConnection conn = connect(address, uuid);
 				if (conn != null) {
 					backoff.reset();
@@ -276,7 +287,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
 
 	@Override
 	public DuplexTransportConnection createConnection(ContactId c) {
-		if (!isRunning()) return null;
+		if (!isRunning() || !shouldAllowContactConnections()) return null;
 		TransportProperties p = callback.getRemoteProperties(c);
 		String address = p.get(PROP_ADDRESS);
 		if (StringUtils.isNullOrEmpty(address)) return null;
@@ -341,6 +352,35 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin {
 		return StringUtils.macToString(mac);
 	}
 
+	@Override
+	public void eventOccurred(Event e) {
+		if (e instanceof EnableBluetoothEvent) {
+			ioExecutor.execute(this::enableAdapter);
+		} else if (e instanceof DisableBluetoothEvent) {
+			ioExecutor.execute(this::disableAdapterIfEnabledByUs);
+		} else if (e instanceof SettingsUpdatedEvent) {
+			SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
+			if (s.getNamespace().equals(ID.getString()))
+				ioExecutor.execute(this::onSettingsUpdated);
+		}
+	}
+
+	private void onSettingsUpdated() {
+		boolean wasAllowed = shouldAllowContactConnections();
+		loadSettings();
+		boolean isAllowed = shouldAllowContactConnections();
+		if (wasAllowed && !isAllowed) {
+			LOG.info("Contact connections disabled");
+			tryToClose(socket);
+			callback.transportDisabled();
+			disableAdapterIfEnabledByUs();
+		} else if (!wasAllowed && isAllowed) {
+			LOG.info("Contact connections enabled");
+			if (isAdapterEnabled()) bind();
+			else enableAdapter();
+		}
+	}
+
 	private class BluetoothKeyAgreementListener extends KeyAgreementListener {
 
 		private final SS ss;
diff --git a/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/DesktopPluginModule.java b/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/DesktopPluginModule.java
index fdd1b4fb9c..288a34b901 100644
--- a/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/DesktopPluginModule.java
+++ b/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/DesktopPluginModule.java
@@ -1,5 +1,6 @@
 package org.briarproject.bramble.plugin;
 
+import org.briarproject.bramble.api.event.EventBus;
 import org.briarproject.bramble.api.lifecycle.IoExecutor;
 import org.briarproject.bramble.api.lifecycle.ShutdownManager;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -30,9 +31,9 @@ public class DesktopPluginModule extends PluginModule {
 	PluginConfig getPluginConfig(@IoExecutor Executor ioExecutor,
 			SecureRandom random, BackoffFactory backoffFactory,
 			ReliabilityLayerFactory reliabilityFactory,
-			ShutdownManager shutdownManager) {
+			ShutdownManager shutdownManager, EventBus eventBus) {
 		DuplexPluginFactory bluetooth =
-				new JavaBluetoothPluginFactory(ioExecutor, random,
+				new JavaBluetoothPluginFactory(ioExecutor, random, eventBus,
 						backoffFactory);
 		DuplexPluginFactory modem = new ModemPluginFactory(ioExecutor,
 				reliabilityFactory);
diff --git a/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPlugin.java b/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPlugin.java
index 02bf0e8f09..a6086f4c3e 100644
--- a/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPlugin.java
+++ b/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPlugin.java
@@ -47,7 +47,7 @@ class JavaBluetoothPlugin extends BluetoothPlugin<StreamConnectionNotifier> {
 
 	@Override
 	boolean isAdapterEnabled() {
-		return LocalDevice.isPowerOn();
+		return localDevice != null && LocalDevice.isPowerOn();
 	}
 
 	@Override
@@ -56,6 +56,11 @@ class JavaBluetoothPlugin extends BluetoothPlugin<StreamConnectionNotifier> {
 		LOG.info("Could not enable Bluetooth");
 	}
 
+	@Override
+	void disableAdapterIfEnabledByUs() {
+		// We didn't enable it so we don't need to disable it
+	}
+
 	@Nullable
 	@Override
 	String getBluetoothAddress() {
diff --git a/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPluginFactory.java b/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPluginFactory.java
index f5ddaed332..56e7234f62 100644
--- a/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPluginFactory.java
+++ b/bramble-j2se/src/main/java/org/briarproject/bramble/plugin/bluetooth/JavaBluetoothPluginFactory.java
@@ -1,5 +1,6 @@
 package org.briarproject.bramble.plugin.bluetooth;
 
+import org.briarproject.bramble.api.event.EventBus;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.plugin.Backoff;
 import org.briarproject.bramble.api.plugin.BackoffFactory;
@@ -27,12 +28,15 @@ public class JavaBluetoothPluginFactory implements DuplexPluginFactory {
 	private final Executor ioExecutor;
 	private final SecureRandom secureRandom;
 	private final BackoffFactory backoffFactory;
+	private final EventBus eventBus;
 
 	public JavaBluetoothPluginFactory(Executor ioExecutor,
-			SecureRandom secureRandom, BackoffFactory backoffFactory) {
+			SecureRandom secureRandom, EventBus eventBus,
+			BackoffFactory backoffFactory) {
 		this.ioExecutor = ioExecutor;
 		this.secureRandom = secureRandom;
 		this.backoffFactory = backoffFactory;
+		this.eventBus = eventBus;
 	}
 
 	@Override
@@ -49,7 +53,9 @@ public class JavaBluetoothPluginFactory implements DuplexPluginFactory {
 	public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
 		Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
 				MAX_POLLING_INTERVAL, BACKOFF_BASE);
-		return new JavaBluetoothPlugin(ioExecutor, secureRandom, backoff,
-				callback, MAX_LATENCY);
+		JavaBluetoothPlugin plugin = new JavaBluetoothPlugin(ioExecutor,
+				secureRandom, backoff, callback, MAX_LATENCY);
+		eventBus.addListener(plugin);
+		return plugin;
 	}
 }
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
index 4c0b80840a..d781e6bffb 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
@@ -22,8 +22,6 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
 import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
 import org.briarproject.bramble.api.plugin.BluetoothConstants;
 import org.briarproject.bramble.api.plugin.TorConstants;
-import org.briarproject.bramble.api.plugin.event.DisableBluetoothEvent;
-import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
 import org.briarproject.bramble.api.settings.Settings;
 import org.briarproject.bramble.api.settings.SettingsManager;
 import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
@@ -262,7 +260,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
 	public boolean onPreferenceChange(Preference preference, Object o) {
 		if (preference == enableBluetooth) {
 			boolean btSetting = Boolean.valueOf((String) o);
-			enableOrDisableBluetooth(btSetting);
 			storeBluetoothSettings(btSetting);
 		} else if (preference == torNetwork) {
 			int torSetting = Integer.valueOf((String) o);
@@ -295,11 +292,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
 		return true;
 	}
 
-	private void enableOrDisableBluetooth(boolean enable) {
-		if (enable) eventBus.broadcast(new EnableBluetoothEvent());
-		else eventBus.broadcast(new DisableBluetoothEvent());
-	}
-
 	private void storeTorSettings(int torSetting) {
 		listener.runOnDbThread(() -> {
 			try {
-- 
GitLab