Enable BT plugin before showing QR code.

This commit is contained in:
akwizgran
2020-01-17 10:32:01 +00:00
parent c67f758c90
commit 413ce29c0c

View File

@@ -8,10 +8,20 @@ import android.content.IntentFilter;
import android.os.Bundle; import android.os.Bundle;
import android.view.MenuItem; import android.view.MenuItem;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.BluetoothConstants;
import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.plugin.PluginManager;
import org.briarproject.bramble.api.plugin.event.BluetoothEnabledEvent; import org.briarproject.bramble.api.plugin.event.BluetoothEnabledEvent;
import org.briarproject.bramble.api.plugin.event.TransportActiveEvent;
import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.settings.SettingsManager;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity; import org.briarproject.briar.android.activity.BriarActivity;
@@ -21,6 +31,7 @@ import org.briarproject.briar.android.keyagreement.IntroFragment.IntroScreenSeen
import org.briarproject.briar.android.keyagreement.KeyAgreementFragment.KeyAgreementEventListener; import org.briarproject.briar.android.keyagreement.KeyAgreementFragment.KeyAgreementEventListener;
import org.briarproject.briar.android.util.UiUtils; import org.briarproject.briar.android.util.UiUtils;
import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -37,15 +48,15 @@ import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.CAMERA; import static android.Manifest.permission.CAMERA;
import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE; import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE;
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED; import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE; import static android.bluetooth.BluetoothAdapter.EXTRA_SCAN_MODE;
import static android.bluetooth.BluetoothAdapter.EXTRA_STATE;
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE;
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
import static android.bluetooth.BluetoothAdapter.STATE_ON;
import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PREF_BT_ENABLE;
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_BLUETOOTH_DISCOVERABLE; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_BLUETOOTH_DISCOVERABLE;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PERMISSION_CAMERA_LOCATION; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PERMISSION_CAMERA_LOCATION;
@@ -53,10 +64,41 @@ import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PERMI
@ParametersNotNullByDefault @ParametersNotNullByDefault
public abstract class KeyAgreementActivity extends BriarActivity implements public abstract class KeyAgreementActivity extends BriarActivity implements
BaseFragmentListener, IntroScreenSeenListener, BaseFragmentListener, IntroScreenSeenListener,
KeyAgreementEventListener { KeyAgreementEventListener, EventListener {
private enum BluetoothState { private enum BluetoothState {
UNKNOWN, NO_ADAPTER, WAITING, REFUSED, ENABLED, DISCOVERABLE /**
* We don't yet know the state of the Bluetooth adapter or plugin.
*/
UNKNOWN,
/**
* The device doesn't have a Bluetooth adapter.
*/
NO_ADAPTER,
/**
* We're waiting for the user to decide whether to allow
* discoverability, or the user has allowed discoverability and we're
* waiting for the adapter to become discoverable.
*/
WAITING,
/**
* The user has refused discoverability.
*/
REFUSED,
/**
* The Bluetooth adapter is discoverable.
*/
DISCOVERABLE,
/**
* The Bluetooth adapter is discoverable and we're waiting for the
* Bluetooth plugin to become active.
*/
ACTIVATING_PLUGIN
} }
private enum Permission { private enum Permission {
@@ -69,6 +111,16 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
@Inject @Inject
EventBus eventBus; EventBus eventBus;
@Inject
PluginManager pluginManager;
@Inject
@IoExecutor
Executor ioExecutor;
@Inject
SettingsManager settingsManager;
/** /**
* Set to true in onPostResume() and false in onPause(). This prevents the * Set to true in onPostResume() and false in onPause(). This prevents the
* QR code fragment from being shown if onRequestPermissionsResult() is * QR code fragment from being shown if onRequestPermissionsResult() is
@@ -91,6 +143,13 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
*/ */
private boolean wasAdapterEnabled = false; private boolean wasAdapterEnabled = false;
/**
* Records whether the user accepted the most recent request (if any) to
* make the Bluetooth adapter discoverable, so we know whether to broadcast
* a {@link BluetoothEnabledEvent}.
*/
private boolean wasRequestAccepted = false;
private Permission cameraPermission = Permission.UNKNOWN; private Permission cameraPermission = Permission.UNKNOWN;
private Permission locationPermission = Permission.UNKNOWN; private Permission locationPermission = Permission.UNKNOWN;
private BluetoothState bluetoothState = BluetoothState.UNKNOWN; private BluetoothState bluetoothState = BluetoothState.UNKNOWN;
@@ -111,9 +170,7 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
if (state == null) { if (state == null) {
showInitialFragment(IntroFragment.newInstance()); showInitialFragment(IntroFragment.newInstance());
} }
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED);
filter.addAction(ACTION_STATE_CHANGED);
filter.addAction(ACTION_SCAN_MODE_CHANGED);
bluetoothReceiver = new BluetoothStateReceiver(); bluetoothReceiver = new BluetoothStateReceiver();
registerReceiver(bluetoothReceiver, filter); registerReceiver(bluetoothReceiver, filter);
} }
@@ -136,6 +193,7 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
eventBus.addListener(this);
// Permissions may have been granted manually while we were stopped // Permissions may have been granted manually while we were stopped
cameraPermission = Permission.UNKNOWN; cameraPermission = Permission.UNKNOWN;
locationPermission = Permission.UNKNOWN; locationPermission = Permission.UNKNOWN;
@@ -152,11 +210,22 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
private void showQrCodeFragmentIfAllowed() { private void showQrCodeFragmentIfAllowed() {
if (isResumed && continueClicked && areEssentialPermissionsGranted()) { if (isResumed && continueClicked && areEssentialPermissionsGranted()) {
if (bluetoothState == BluetoothState.UNKNOWN || if (bluetoothState == BluetoothState.UNKNOWN) {
bluetoothState == BluetoothState.ENABLED) {
requestBluetoothDiscoverable(); requestBluetoothDiscoverable();
} else if (bluetoothState != BluetoothState.WAITING) { } else if (bluetoothState == BluetoothState.NO_ADAPTER ||
bluetoothState == BluetoothState.REFUSED) {
LOG.info("Continuing without Bluetooth");
showQrCodeFragment(); showQrCodeFragment();
} else if (bluetoothState == BluetoothState.DISCOVERABLE ||
bluetoothState == BluetoothState.ACTIVATING_PLUGIN) {
if (isBluetoothPluginActive()) {
LOG.info("Bluetooth plugin is active");
showQrCodeFragment();
} else {
LOG.info("Enabling Bluetooth plugin");
bluetoothState = BluetoothState.ACTIVATING_PLUGIN;
enableBluetoothPlugin();
}
} }
} }
} }
@@ -169,12 +238,36 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
locationPermission == Permission.PERMANENTLY_DENIED); locationPermission == Permission.PERMANENTLY_DENIED);
} }
private boolean isBluetoothPluginActive() {
Plugin p = pluginManager.getPlugin(BluetoothConstants.ID);
return p != null && p.getState() == ACTIVE;
}
private void enableBluetoothPlugin() {
ioExecutor.execute(() -> {
try {
Settings s = new Settings();
s.putBoolean(PREF_BT_ENABLE, true);
String namespace = BluetoothConstants.ID.getString();
settingsManager.mergeSettings(s, namespace);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
}
@Override @Override
protected void onPause() { protected void onPause() {
super.onPause(); super.onPause();
isResumed = false; isResumed = false;
} }
@Override
protected void onStop() {
super.onStop();
eventBus.removeListener(this);
}
@Override @Override
public void showNextScreen() { public void showNextScreen() {
continueClicked = true; continueClicked = true;
@@ -200,8 +293,11 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
private void setBluetoothState(BluetoothState bluetoothState) { private void setBluetoothState(BluetoothState bluetoothState) {
LOG.info("Setting Bluetooth state to " + bluetoothState); LOG.info("Setting Bluetooth state to " + bluetoothState);
this.bluetoothState = bluetoothState; this.bluetoothState = bluetoothState;
if (!wasAdapterEnabled && bluetoothState == BluetoothState.ENABLED) { if (!wasAdapterEnabled && wasRequestAccepted &&
bluetoothState == BluetoothState.DISCOVERABLE) {
LOG.info("Bluetooth adapter was enabled by us");
eventBus.broadcast(new BluetoothEnabledEvent()); eventBus.broadcast(new BluetoothEnabledEvent());
wasRequestAccepted = false;
wasAdapterEnabled = true; wasAdapterEnabled = true;
} }
showQrCodeFragmentIfAllowed(); showQrCodeFragmentIfAllowed();
@@ -214,12 +310,14 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
if (result == RESULT_CANCELED) { if (result == RESULT_CANCELED) {
setBluetoothState(BluetoothState.REFUSED); setBluetoothState(BluetoothState.REFUSED);
} else { } else {
wasRequestAccepted = true;
// If Bluetooth is already discoverable, show the QR code - // If Bluetooth is already discoverable, show the QR code -
// otherwise wait for the state or scan mode to change // otherwise wait for the state or scan mode to change
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
if (bt == null) throw new AssertionError(); if (bt == null) throw new AssertionError();
if (bt.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE) if (bt.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
setBluetoothState(BluetoothState.DISCOVERABLE); setBluetoothState(BluetoothState.DISCOVERABLE);
}
} }
} else super.onActivityResult(request, result, data); } else super.onActivityResult(request, result, data);
} }
@@ -332,23 +430,30 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
permission); permission);
} }
@Override
public void eventOccurred(Event e) {
if (e instanceof TransportActiveEvent) {
TransportActiveEvent t = (TransportActiveEvent) e;
if (t.getTransportId().equals(BluetoothConstants.ID)) {
showQrCodeFragmentIfAllowed();
}
}
}
private class BluetoothStateReceiver extends BroadcastReceiver { private class BluetoothStateReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
String action = intent.getAction(); String action = intent.getAction();
if (ACTION_STATE_CHANGED.equals(action)) { if (ACTION_SCAN_MODE_CHANGED.equals(action)) {
int state = intent.getIntExtra(EXTRA_STATE, 0);
if (state == STATE_ON)
setBluetoothState(BluetoothState.ENABLED);
else setBluetoothState(BluetoothState.UNKNOWN);
} else if (ACTION_SCAN_MODE_CHANGED.equals(action)) {
int scanMode = intent.getIntExtra(EXTRA_SCAN_MODE, 0); int scanMode = intent.getIntExtra(EXTRA_SCAN_MODE, 0);
if (scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE) if (scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
LOG.info("Bluetooth adapter is discoverable");
setBluetoothState(BluetoothState.DISCOVERABLE); setBluetoothState(BluetoothState.DISCOVERABLE);
else if (scanMode == SCAN_MODE_CONNECTABLE) } else if (bluetoothState == BluetoothState.DISCOVERABLE) {
setBluetoothState(BluetoothState.ENABLED); LOG.info("Bluetooth adapter is not discoverable");
else setBluetoothState(BluetoothState.UNKNOWN); setBluetoothState(BluetoothState.UNKNOWN);
}
} }
} }
} }