Ask before turning on Bluetooth to add a contact.

This commit is contained in:
akwizgran
2018-01-05 18:03:56 +00:00
parent 19be4d6edf
commit fc50bb1c6c
8 changed files with 130 additions and 46 deletions

View File

@@ -120,6 +120,11 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
} }
} }
@Override
void setEnabledByUs() {
wasEnabledByUs = true;
}
@Override @Override
@Nullable @Nullable
String getBluetoothAddress() { String getBluetoothAddress() {

View File

@@ -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 {
}

View File

@@ -6,7 +6,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable; 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 @Immutable
@NotNullByDefault @NotNullByDefault

View File

@@ -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.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; 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.DisableBluetoothEvent;
import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent; import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportProperties;
@@ -51,8 +52,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(BluetoothPlugin.class.getName()); Logger.getLogger(BluetoothPlugin.class.getName());
final Executor ioExecutor; private final Executor ioExecutor;
private final SecureRandom secureRandom; private final SecureRandom secureRandom;
private final Backoff backoff; private final Backoff backoff;
private final DuplexPluginCallback callback; private final DuplexPluginCallback callback;
@@ -70,6 +70,8 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
abstract void disableAdapterIfEnabledByUs(); abstract void disableAdapterIfEnabledByUs();
abstract void setEnabledByUs();
@Nullable @Nullable
abstract String getBluetoothAddress(); abstract String getBluetoothAddress();
@@ -358,6 +360,8 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
ioExecutor.execute(this::enableAdapter); ioExecutor.execute(this::enableAdapter);
} else if (e instanceof DisableBluetoothEvent) { } else if (e instanceof DisableBluetoothEvent) {
ioExecutor.execute(this::disableAdapterIfEnabledByUs); ioExecutor.execute(this::disableAdapterIfEnabledByUs);
} else if (e instanceof BluetoothEnabledEvent) {
setEnabledByUs();
} else if (e instanceof SettingsUpdatedEvent) { } else if (e instanceof SettingsUpdatedEvent) {
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e; SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
if (s.getNamespace().equals(ID.getString())) if (s.getNamespace().equals(ID.getString()))

View File

@@ -61,6 +61,11 @@ class JavaBluetoothPlugin extends BluetoothPlugin<StreamConnectionNotifier> {
// We didn't enable it so we don't need to disable it // We didn't enable it so we don't need to disable it
} }
@Override
void setEnabledByUs() {
// Irrelevant on this platform
}
@Nullable @Nullable
@Override @Override
String getBluetoothAddress() { String getBluetoothAddress() {

View File

@@ -11,5 +11,6 @@ public interface RequestCodes {
int REQUEST_RINGTONE = 7; int REQUEST_RINGTONE = 7;
int REQUEST_PERMISSION_CAMERA = 8; int REQUEST_PERMISSION_CAMERA = 8;
int REQUEST_DOZE_WHITELISTING = 9; int REQUEST_DOZE_WHITELISTING = 9;
int REQUEST_ENABLE_BLUETOOTH = 10;
} }

View File

@@ -1,6 +1,11 @@
package org.briarproject.briar.android.keyagreement; 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.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.UiThread; import android.support.annotation.UiThread;
import android.support.v4.app.ActivityCompat; 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.keyagreement.event.KeyAgreementFinishedEvent;
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.event.BluetoothEnabledEvent;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.R.string; import org.briarproject.briar.R.string;
import org.briarproject.briar.R.style; import org.briarproject.briar.R.style;
@@ -39,9 +45,15 @@ import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import static android.Manifest.permission.CAMERA; 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.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Build.VERSION.SDK_INT;
import static android.widget.Toast.LENGTH_LONG; import static android.widget.Toast.LENGTH_LONG;
import static java.util.logging.Level.WARNING; 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; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PERMISSION_CAMERA;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@@ -50,6 +62,10 @@ public class KeyAgreementActivity extends BriarActivity implements
BaseFragmentListener, IntroScreenSeenListener, EventListener, BaseFragmentListener, IntroScreenSeenListener, EventListener,
ContactExchangeListener { ContactExchangeListener {
private enum BluetoothState {
UNKNOWN, NO_ADAPTER, WAITING, REFUSED, ENABLED
}
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(KeyAgreementActivity.class.getName()); Logger.getLogger(KeyAgreementActivity.class.getName());
@@ -62,7 +78,10 @@ public class KeyAgreementActivity extends BriarActivity implements
@Inject @Inject
volatile IdentityManager identityManager; volatile IdentityManager identityManager;
private boolean isResumed = false, enableWasRequested = false;
private boolean continueClicked, gotCameraPermission; private boolean continueClicked, gotCameraPermission;
private BluetoothState bluetoothState = BluetoothState.UNKNOWN;
private BroadcastReceiver bluetoothReceiver = null;
@Override @Override
public void injectActivity(ActivityComponent component) { public void injectActivity(ActivityComponent component) {
@@ -84,6 +103,15 @@ public class KeyAgreementActivity extends BriarActivity implements
if (state == null) { if (state == null) {
showInitialFragment(IntroFragment.newInstance()); 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 @Override
@@ -112,24 +140,72 @@ public class KeyAgreementActivity extends BriarActivity implements
@Override @Override
protected void onPostResume() { protected void onPostResume() {
super.onPostResume(); super.onPostResume();
isResumed = true;
// Workaround for // Workaround for
// https://code.google.com/p/android/issues/detail?id=190966 // https://code.google.com/p/android/issues/detail?id=190966
if (continueClicked && gotCameraPermission) { if (canShowQrCodeFragment()) showQrCodeFragment();
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 @Override
public void showNextScreen() { public void showNextScreen() {
// FIXME #824
// showNextFragment(ShowQrCodeFragment.newInstance());
continueClicked = true; continueClicked = true;
if (checkPermissions()) { 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() { private void showQrCodeFragment() {
// FIXME #824
BaseFragment f = ShowQrCodeFragment.newInstance(); BaseFragment f = ShowQrCodeFragment.newInstance();
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, f, f.getUniqueTag()) .replace(R.id.fragmentContainer, f, f.getUniqueTag())
@@ -154,8 +230,10 @@ public class KeyAgreementActivity extends BriarActivity implements
} else { } else {
requestPermission(); requestPermission();
} }
gotCameraPermission = false;
return false; return false;
} else { } else {
gotCameraPermission = true;
return true; return true;
} }
} }
@@ -174,6 +252,7 @@ public class KeyAgreementActivity extends BriarActivity implements
if (grantResults.length > 0 && if (grantResults.length > 0 &&
grantResults[0] == PERMISSION_GRANTED) { grantResults[0] == PERMISSION_GRANTED) {
gotCameraPermission = true; gotCameraPermission = true;
showNextScreen();
} else { } else {
if (!ActivityCompat.shouldShowRequestPermissionRationale(this, if (!ActivityCompat.shouldShowRequestPermissionRationale(this,
CAMERA)) { CAMERA)) {
@@ -258,4 +337,14 @@ public class KeyAgreementActivity extends BriarActivity implements
finish(); 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);
}
}
} }

View File

@@ -1,10 +1,6 @@
package org.briarproject.briar.android.keyagreement; package org.briarproject.briar.android.keyagreement;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.hardware.Camera; import android.hardware.Camera;
import android.os.AsyncTask; import android.os.AsyncTask;
@@ -40,7 +36,6 @@ import org.briarproject.bramble.api.keyagreement.event.KeyAgreementWaitingEvent;
import org.briarproject.bramble.api.lifecycle.IoExecutor; 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.event.EnableBluetoothEvent;
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.fragment.BaseEventFragment; import org.briarproject.briar.android.fragment.BaseEventFragment;
@@ -52,9 +47,6 @@ import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
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.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
import static android.view.View.INVISIBLE; import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
@@ -89,8 +81,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
private TextView mainProgressTitle; private TextView mainProgressTitle;
private ViewGroup mainProgressContainer; private ViewGroup mainProgressContainer;
private BluetoothStateReceiver receiver; private boolean gotRemotePayload;
private boolean gotRemotePayload, waitingForBluetooth;
private volatile boolean gotLocalPayload; private volatile boolean gotLocalPayload;
private KeyAgreementTask task; private KeyAgreementTask task;
@@ -151,20 +142,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
} catch (CameraException e) { } catch (CameraException e) {
logCameraExceptionAndFinish(e); logCameraExceptionAndFinish(e);
} }
// Listen for changes to the Bluetooth state startListening();
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();
}
} }
/** /**
@@ -190,7 +168,6 @@ public class ShowQrCodeFragment extends BaseEventFragment
public void onStop() { public void onStop() {
super.onStop(); super.onStop();
stopListening(); stopListening();
if (receiver != null) getActivity().unregisterReceiver(receiver);
try { try {
cameraView.stop(); cameraView.stop();
} catch (CameraException e) { } catch (CameraException e) {
@@ -362,16 +339,4 @@ public class ShowQrCodeFragment extends BaseEventFragment
protected void finish() { protected void finish() {
getActivity().getSupportFragmentManager().popBackStack(); 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();
}
}
}
} }