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 8bbfe971d235a29797077a10eccc957655ed431d..6adbd5adb83d8ea038d12b24307a185959aa497b 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 4da5916f4a00bb2df604716bc9cda395aaf5aec3..bafd0649fcc092b3bc39398d1210e92d4bd708b2 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 fdd1b4fb9c3e1cf053b9aeb876c9fa4985aabe2b..288a34b901d93c7f936e2fa1b948806d4bd1bb09 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 02bf0e8f09710ff74144c798d2f7fd8e7b42d117..a6086f4c3e0c51bc0405364a6d795342661d5912 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 f5ddaed332b5cc3d5194696deb68bd7fc349b45a..56e7234f6228fc4e7deb81025b0b88ae08653cf0 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 4c0b80840aa51ee1b54427af08441b4d8f316770..d781e6bffb31219d3aad980e4c13a0beb2a4342d 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 {