Merge branch '790-ask-before-turning-on-bluetooth' into 'maintenance-0.16'

Backport: Ask before turning on Bluetooth to add a contact

See merge request akwizgran/briar!723
This commit is contained in:
akwizgran
2018-03-07 14:04:09 +00:00
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
@Nullable
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 javax.annotation.concurrent.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;
/**
* 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

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.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()))

View File

@@ -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() {

View File

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

View File

@@ -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);
}
}
}

View File

@@ -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.hardware.Camera;
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.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;
@@ -52,9 +47,6 @@ import java.util.logging.Logger;
import javax.annotation.Nullable;
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.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
@@ -89,8 +81,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;
@@ -151,20 +142,7 @@ 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();
}
/**
@@ -190,7 +168,6 @@ public class ShowQrCodeFragment extends BaseEventFragment
public void onStop() {
super.onStop();
stopListening();
if (receiver != null) getActivity().unregisterReceiver(receiver);
try {
cameraView.stop();
} catch (CameraException e) {
@@ -362,16 +339,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();
}
}
}
}