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 1a90232206824a410f3cb0c032b0cc316e6c519b..2c318a6493722db272b75afa698321e128c694c7 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
@@ -120,6 +120,11 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
 		}
 	}
 
+	@Override
+	void setEnabledByUs() {
+		wasEnabledByUs = true;
+	}
+
 	@Override
 	@Nullable
 	String getBluetoothAddress() {
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/BluetoothEnabledEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/BluetoothEnabledEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..41fa2bdbe16de26720b284a2152bf025f954b9a7
--- /dev/null
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/BluetoothEnabledEvent.java
@@ -0,0 +1,15 @@
+package org.briarproject.bramble.api.plugin.event;
+
+import org.briarproject.bramble.api.event.Event;
+import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
+
+import jdk.nashorn.internal.ir.annotations.Immutable;
+
+/**
+ * An event that informs the Bluetooth plugin that we have enabled the
+ * Bluetooth adapter.
+ */
+@Immutable
+@NotNullByDefault
+public class BluetoothEnabledEvent extends Event {
+}
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/EnableBluetoothEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/EnableBluetoothEvent.java
index 148e55e6e3f2ddf57b40c8aa2f66b2a7bbf82e7c..659b5a16b649cf64a15f9fd48a505ae40748e9a4 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/EnableBluetoothEvent.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/EnableBluetoothEvent.java
@@ -6,7 +6,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import javax.annotation.concurrent.Immutable;
 
 /**
- * An event asks the Bluetooth plugin to enable the Bluetooth adapter.
+ * An event that asks the Bluetooth plugin to enable the Bluetooth adapter.
  */
 @Immutable
 @NotNullByDefault
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 bafd0649fcc092b3bc39398d1210e92d4bd708b2..4f7afa0349d3f4f6fa97cecce57f1c5614f97af1 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
@@ -15,6 +15,7 @@ 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.BluetoothEnabledEvent;
 import org.briarproject.bramble.api.plugin.event.DisableBluetoothEvent;
 import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
 import org.briarproject.bramble.api.properties.TransportProperties;
@@ -51,8 +52,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
 	private static final Logger LOG =
 			Logger.getLogger(BluetoothPlugin.class.getName());
 
-	final Executor ioExecutor;
-
+	private final Executor ioExecutor;
 	private final SecureRandom secureRandom;
 	private final Backoff backoff;
 	private final DuplexPluginCallback callback;
@@ -70,6 +70,8 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
 
 	abstract void disableAdapterIfEnabledByUs();
 
+	abstract void setEnabledByUs();
+
 	@Nullable
 	abstract String getBluetoothAddress();
 
@@ -358,6 +360,8 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
 			ioExecutor.execute(this::enableAdapter);
 		} else if (e instanceof DisableBluetoothEvent) {
 			ioExecutor.execute(this::disableAdapterIfEnabledByUs);
+		} else if (e instanceof BluetoothEnabledEvent) {
+			setEnabledByUs();
 		} else if (e instanceof SettingsUpdatedEvent) {
 			SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
 			if (s.getNamespace().equals(ID.getString()))
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 a6086f4c3e0c51bc0405364a6d795342661d5912..487603e2da837b107711c2c5dd02a3a20eea3ba7 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
@@ -61,6 +61,11 @@ class JavaBluetoothPlugin extends BluetoothPlugin<StreamConnectionNotifier> {
 		// We didn't enable it so we don't need to disable it
 	}
 
+	@Override
+	void setEnabledByUs() {
+		// Irrelevant on this platform
+	}
+
 	@Nullable
 	@Override
 	String getBluetoothAddress() {
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java
index fe771c430c0877a6c6f06ab81bcac7d8e70d3e92..4b8caa3d2004eef63ac34810d9aa0157b291e515 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java
@@ -11,5 +11,6 @@ public interface RequestCodes {
 	int REQUEST_RINGTONE = 7;
 	int REQUEST_PERMISSION_CAMERA = 8;
 	int REQUEST_DOZE_WHITELISTING = 9;
+	int REQUEST_ENABLE_BLUETOOTH = 10;
 
 }
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/KeyAgreementActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/KeyAgreementActivity.java
index 040312127b7f850a007d6dd82fc6f27e632a8997..c960ffe9bf06430c71b829f3b626adab5dfbb6f6 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/KeyAgreementActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/KeyAgreementActivity.java
@@ -1,6 +1,11 @@
 package org.briarproject.briar.android.keyagreement;
 
+import android.bluetooth.BluetoothAdapter;
+import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.Bundle;
 import android.support.annotation.UiThread;
 import android.support.v4.app.ActivityCompat;
@@ -23,6 +28,7 @@ import org.briarproject.bramble.api.keyagreement.KeyAgreementResult;
 import org.briarproject.bramble.api.keyagreement.event.KeyAgreementFinishedEvent;
 import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
 import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
+import org.briarproject.bramble.api.plugin.event.BluetoothEnabledEvent;
 import org.briarproject.briar.R;
 import org.briarproject.briar.R.string;
 import org.briarproject.briar.R.style;
@@ -39,9 +45,15 @@ import javax.annotation.Nullable;
 import javax.inject.Inject;
 
 import static android.Manifest.permission.CAMERA;
+import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_ENABLE;
+import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
+import static android.bluetooth.BluetoothAdapter.EXTRA_STATE;
+import static android.bluetooth.BluetoothAdapter.STATE_ON;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Build.VERSION.SDK_INT;
 import static android.widget.Toast.LENGTH_LONG;
 import static java.util.logging.Level.WARNING;
+import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_ENABLE_BLUETOOTH;
 import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PERMISSION_CAMERA;
 
 @MethodsNotNullByDefault
@@ -50,6 +62,10 @@ public class KeyAgreementActivity extends BriarActivity implements
 		BaseFragmentListener, IntroScreenSeenListener, EventListener,
 		ContactExchangeListener {
 
+	private enum BluetoothState {
+		UNKNOWN, NO_ADAPTER, WAITING, REFUSED, ENABLED
+	}
+
 	private static final Logger LOG =
 			Logger.getLogger(KeyAgreementActivity.class.getName());
 
@@ -62,7 +78,10 @@ public class KeyAgreementActivity extends BriarActivity implements
 	@Inject
 	volatile IdentityManager identityManager;
 
+	private boolean isResumed = false, enableWasRequested = false;
 	private boolean continueClicked, gotCameraPermission;
+	private BluetoothState bluetoothState = BluetoothState.UNKNOWN;
+	private BroadcastReceiver bluetoothReceiver = null;
 
 	@Override
 	public void injectActivity(ActivityComponent component) {
@@ -84,6 +103,15 @@ public class KeyAgreementActivity extends BriarActivity implements
 		if (state == null) {
 			showInitialFragment(IntroFragment.newInstance());
 		}
+		IntentFilter filter = new IntentFilter(ACTION_STATE_CHANGED);
+		bluetoothReceiver = new BluetoothStateReceiver();
+		registerReceiver(bluetoothReceiver, filter);
+	}
+
+	@Override
+	public void onDestroy() {
+		super.onDestroy();
+		if (bluetoothReceiver != null) unregisterReceiver(bluetoothReceiver);
 	}
 
 	@Override
@@ -112,24 +140,72 @@ public class KeyAgreementActivity extends BriarActivity implements
 	@Override
 	protected void onPostResume() {
 		super.onPostResume();
+		isResumed = true;
 		// Workaround for
 		// https://code.google.com/p/android/issues/detail?id=190966
-		if (continueClicked && gotCameraPermission) {
-			showQrCodeFragment();
-		}
+		if (canShowQrCodeFragment()) showQrCodeFragment();
+	}
+
+	boolean canShowQrCodeFragment() {
+		return isResumed && continueClicked
+				&& (SDK_INT < 23 || gotCameraPermission)
+				&& bluetoothState != BluetoothState.UNKNOWN
+				&& bluetoothState != BluetoothState.WAITING;
+	}
+
+	@Override
+	protected void onPause() {
+		super.onPause();
+		isResumed = false;
 	}
 
 	@Override
 	public void showNextScreen() {
-		// FIXME #824
-		// showNextFragment(ShowQrCodeFragment.newInstance());
 		continueClicked = true;
 		if (checkPermissions()) {
-			showQrCodeFragment();
+			if (shouldRequestEnableBluetooth()) requestEnableBluetooth();
+			else if (canShowQrCodeFragment()) showQrCodeFragment();
 		}
 	}
 
+	private boolean shouldRequestEnableBluetooth() {
+		return bluetoothState == BluetoothState.UNKNOWN
+				|| bluetoothState == BluetoothState.REFUSED;
+	}
+
+	private void requestEnableBluetooth() {
+		BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
+		if (bt == null) {
+			setBluetoothState(BluetoothState.NO_ADAPTER);
+		} else if (bt.isEnabled()) {
+			setBluetoothState(BluetoothState.ENABLED);
+		} else {
+			enableWasRequested = true;
+			setBluetoothState(BluetoothState.WAITING);
+			Intent i = new Intent(ACTION_REQUEST_ENABLE);
+			startActivityForResult(i, REQUEST_ENABLE_BLUETOOTH);
+		}
+	}
+
+	private void setBluetoothState(BluetoothState bluetoothState) {
+		LOG.info("Setting Bluetooth state to " + bluetoothState);
+		this.bluetoothState = bluetoothState;
+		if (enableWasRequested && bluetoothState == BluetoothState.ENABLED) {
+			eventBus.broadcast(new BluetoothEnabledEvent());
+			enableWasRequested = false;
+		}
+		if (canShowQrCodeFragment()) showQrCodeFragment();
+	}
+
+	@Override
+	public void onActivityResult(int request, int result, Intent data) {
+		// If the request was granted we'll catch the state change event
+		if (request == REQUEST_ENABLE_BLUETOOTH && result == RESULT_CANCELED)
+			setBluetoothState(BluetoothState.REFUSED);
+	}
+
 	private void showQrCodeFragment() {
+		// FIXME #824
 		BaseFragment f = ShowQrCodeFragment.newInstance();
 		getSupportFragmentManager().beginTransaction()
 				.replace(R.id.fragmentContainer, f, f.getUniqueTag())
@@ -154,8 +230,10 @@ public class KeyAgreementActivity extends BriarActivity implements
 			} else {
 				requestPermission();
 			}
+			gotCameraPermission = false;
 			return false;
 		} else {
+			gotCameraPermission = true;
 			return true;
 		}
 	}
@@ -174,6 +252,7 @@ public class KeyAgreementActivity extends BriarActivity implements
 			if (grantResults.length > 0 &&
 					grantResults[0] == PERMISSION_GRANTED) {
 				gotCameraPermission = true;
+				showNextScreen();
 			} else {
 				if (!ActivityCompat.shouldShowRequestPermissionRationale(this,
 						CAMERA)) {
@@ -258,4 +337,14 @@ public class KeyAgreementActivity extends BriarActivity implements
 			finish();
 		});
 	}
+
+	private class BluetoothStateReceiver extends BroadcastReceiver {
+
+		@Override
+		public void onReceive(Context context, Intent intent) {
+			int state = intent.getIntExtra(EXTRA_STATE, 0);
+			if (state == STATE_ON) setBluetoothState(BluetoothState.ENABLED);
+			else setBluetoothState(BluetoothState.UNKNOWN);
+		}
+	}
 }
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ShowQrCodeFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ShowQrCodeFragment.java
index fd0d46445404da75628165430afafab21f88aec5..1ef7dcd2302956920d6f81f6cc6ce1b98d4af319 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ShowQrCodeFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ShowQrCodeFragment.java
@@ -1,10 +1,6 @@
 package org.briarproject.briar.android.keyagreement;
 
-import android.bluetooth.BluetoothAdapter;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.graphics.Bitmap;
 import android.os.AsyncTask;
 import android.os.Bundle;
@@ -36,7 +32,6 @@ import org.briarproject.bramble.api.keyagreement.event.KeyAgreementWaitingEvent;
 import org.briarproject.bramble.api.lifecycle.IoExecutor;
 import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
 import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
-import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
 import org.briarproject.briar.R;
 import org.briarproject.briar.android.activity.ActivityComponent;
 import org.briarproject.briar.android.fragment.BaseEventFragment;
@@ -49,9 +44,6 @@ import javax.annotation.Nullable;
 import javax.inject.Inject;
 import javax.inject.Provider;
 
-import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
-import static android.bluetooth.BluetoothAdapter.EXTRA_STATE;
-import static android.bluetooth.BluetoothAdapter.STATE_ON;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
 import static android.view.View.INVISIBLE;
 import static android.view.View.VISIBLE;
@@ -86,8 +78,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
 	private TextView mainProgressTitle;
 	private ViewGroup mainProgressContainer;
 
-	private BluetoothStateReceiver receiver;
-	private boolean gotRemotePayload, waitingForBluetooth;
+	private boolean gotRemotePayload;
 	private volatile boolean gotLocalPayload;
 	private KeyAgreementTask task;
 
@@ -148,27 +139,13 @@ public class ShowQrCodeFragment extends BaseEventFragment
 		} catch (CameraException e) {
 			logCameraExceptionAndFinish(e);
 		}
-		// Listen for changes to the Bluetooth state
-		IntentFilter filter = new IntentFilter();
-		filter.addAction(ACTION_STATE_CHANGED);
-		receiver = new BluetoothStateReceiver();
-		getActivity().registerReceiver(receiver, filter);
-
-		// Enable BT adapter if it is not already on.
-		BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-		if (adapter != null && !adapter.isEnabled()) {
-			waitingForBluetooth = true;
-			eventBus.broadcast(new EnableBluetoothEvent());
-		} else {
-			startListening();
-		}
+		startListening();
 	}
 
 	@Override
 	public void onStop() {
 		super.onStop();
 		stopListening();
-		if (receiver != null) getActivity().unregisterReceiver(receiver);
 		try {
 			cameraView.stop();
 		} catch (CameraException e) {
@@ -340,16 +317,4 @@ public class ShowQrCodeFragment extends BaseEventFragment
 	protected void finish() {
 		getActivity().getSupportFragmentManager().popBackStack();
 	}
-
-	private class BluetoothStateReceiver extends BroadcastReceiver {
-		@UiThread
-		@Override
-		public void onReceive(Context ctx, Intent intent) {
-			int state = intent.getIntExtra(EXTRA_STATE, 0);
-			if (state == STATE_ON && waitingForBluetooth) {
-				waitingForBluetooth = false;
-				startListening();
-			}
-		}
-	}
 }