mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 14:19:53 +01:00
Require Bluetooth permissions if device supports Bluetooth.
This commit is contained in:
@@ -26,7 +26,6 @@ import org.briarproject.briar.android.fragment.BaseFragment;
|
|||||||
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
||||||
import org.briarproject.briar.android.keyagreement.IntroFragment.IntroScreenSeenListener;
|
import org.briarproject.briar.android.keyagreement.IntroFragment.IntroScreenSeenListener;
|
||||||
import org.briarproject.briar.android.keyagreement.KeyAgreementFragment.KeyAgreementEventListener;
|
import org.briarproject.briar.android.keyagreement.KeyAgreementFragment.KeyAgreementEventListener;
|
||||||
import org.briarproject.briar.android.util.UiUtils;
|
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -55,6 +54,7 @@ import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE;
|
|||||||
import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING;
|
import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING;
|
||||||
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;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.getGoToSettingsListener;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -133,6 +133,8 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
|
|||||||
private Permission locationPermission = Permission.UNKNOWN;
|
private Permission locationPermission = Permission.UNKNOWN;
|
||||||
private BluetoothDecision bluetoothDecision = BluetoothDecision.UNKNOWN;
|
private BluetoothDecision bluetoothDecision = BluetoothDecision.UNKNOWN;
|
||||||
private BroadcastReceiver bluetoothReceiver = null;
|
private BroadcastReceiver bluetoothReceiver = null;
|
||||||
|
private Plugin wifiPlugin = null, bluetoothPlugin = null;
|
||||||
|
private BluetoothAdapter bt = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectActivity(ActivityComponent component) {
|
public void injectActivity(ActivityComponent component) {
|
||||||
@@ -152,6 +154,9 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
|
|||||||
IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED);
|
IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED);
|
||||||
bluetoothReceiver = new BluetoothStateReceiver();
|
bluetoothReceiver = new BluetoothStateReceiver();
|
||||||
registerReceiver(bluetoothReceiver, filter);
|
registerReceiver(bluetoothReceiver, filter);
|
||||||
|
wifiPlugin = pluginManager.getPlugin(LanTcpConstants.ID);
|
||||||
|
bluetoothPlugin = pluginManager.getPlugin(BluetoothConstants.ID);
|
||||||
|
bt = BluetoothAdapter.getDefaultAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -187,6 +192,7 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
|
|||||||
showQrCodeFragmentIfAllowed();
|
showQrCodeFragmentIfAllowed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("StatementWithEmptyBody")
|
||||||
private void showQrCodeFragmentIfAllowed() {
|
private void showQrCodeFragmentIfAllowed() {
|
||||||
if (isResumed && continueClicked && areEssentialPermissionsGranted()) {
|
if (isResumed && continueClicked && areEssentialPermissionsGranted()) {
|
||||||
if (isWifiReady() && isBluetoothReady()) {
|
if (isWifiReady() && isBluetoothReady()) {
|
||||||
@@ -200,6 +206,8 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
|
|||||||
}
|
}
|
||||||
if (bluetoothDecision == BluetoothDecision.UNKNOWN) {
|
if (bluetoothDecision == BluetoothDecision.UNKNOWN) {
|
||||||
requestBluetoothDiscoverable();
|
requestBluetoothDiscoverable();
|
||||||
|
} else if (bluetoothDecision == BluetoothDecision.REFUSED) {
|
||||||
|
// Ask again when the user clicks "continue"
|
||||||
} else if (shouldEnableBluetooth()) {
|
} else if (shouldEnableBluetooth()) {
|
||||||
LOG.info("Enabling Bluetooth plugin");
|
LOG.info("Enabling Bluetooth plugin");
|
||||||
hasEnabledBluetooth = true;
|
hasEnabledBluetooth = true;
|
||||||
@@ -210,55 +218,50 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean areEssentialPermissionsGranted() {
|
private boolean areEssentialPermissionsGranted() {
|
||||||
// If the camera permission has been granted, and the location
|
|
||||||
// permission has been granted or permanently denied, we can continue
|
|
||||||
return cameraPermission == Permission.GRANTED &&
|
return cameraPermission == Permission.GRANTED &&
|
||||||
(locationPermission == Permission.GRANTED ||
|
(locationPermission == Permission.GRANTED ||
|
||||||
locationPermission == Permission.PERMANENTLY_DENIED);
|
!isBluetoothSupported());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBluetoothSupported() {
|
||||||
|
return bt != null && bluetoothPlugin != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isWifiReady() {
|
private boolean isWifiReady() {
|
||||||
Plugin p = pluginManager.getPlugin(LanTcpConstants.ID);
|
if (wifiPlugin == null) return true; // Continue without wifi
|
||||||
if (p == null) return true; // Continue without wifi
|
State state = wifiPlugin.getState();
|
||||||
State state = p.getState();
|
|
||||||
// Wait for plugin to become enabled
|
// Wait for plugin to become enabled
|
||||||
return state == ACTIVE || state == INACTIVE;
|
return state == ACTIVE || state == INACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isBluetoothReady() {
|
private boolean isBluetoothReady() {
|
||||||
if (bluetoothDecision == BluetoothDecision.UNKNOWN ||
|
if (!isBluetoothSupported()) {
|
||||||
bluetoothDecision == BluetoothDecision.WAITING) {
|
|
||||||
// Wait for decision
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (bluetoothDecision == BluetoothDecision.NO_ADAPTER
|
|
||||||
|| bluetoothDecision == BluetoothDecision.REFUSED) {
|
|
||||||
// Continue without Bluetooth
|
// Continue without Bluetooth
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
|
if (bluetoothDecision == BluetoothDecision.UNKNOWN ||
|
||||||
if (bt == null) return true; // Continue without Bluetooth
|
bluetoothDecision == BluetoothDecision.WAITING ||
|
||||||
|
bluetoothDecision == BluetoothDecision.REFUSED) {
|
||||||
|
// Wait for user to accept
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (bt.getScanMode() != SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
|
if (bt.getScanMode() != SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
|
||||||
// Wait for adapter to become discoverable
|
// Wait for adapter to become discoverable
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Plugin p = pluginManager.getPlugin(BluetoothConstants.ID);
|
|
||||||
if (p == null) return true; // Continue without Bluetooth
|
|
||||||
// Wait for plugin to become active
|
// Wait for plugin to become active
|
||||||
return p.getState() == ACTIVE;
|
return bluetoothPlugin.getState() == ACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldEnableWifi() {
|
private boolean shouldEnableWifi() {
|
||||||
if (hasEnabledWifi) return false;
|
if (hasEnabledWifi) return false;
|
||||||
Plugin p = pluginManager.getPlugin(LanTcpConstants.ID);
|
if (wifiPlugin == null) return false;
|
||||||
if (p == null) return false;
|
State state = wifiPlugin.getState();
|
||||||
State state = p.getState();
|
|
||||||
return state == STARTING_STOPPING || state == DISABLED;
|
return state == STARTING_STOPPING || state == DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void requestBluetoothDiscoverable() {
|
private void requestBluetoothDiscoverable() {
|
||||||
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
|
if (!isBluetoothSupported()) {
|
||||||
if (bt == null) {
|
|
||||||
bluetoothDecision = BluetoothDecision.NO_ADAPTER;
|
bluetoothDecision = BluetoothDecision.NO_ADAPTER;
|
||||||
showQrCodeFragmentIfAllowed();
|
showQrCodeFragmentIfAllowed();
|
||||||
} else {
|
} else {
|
||||||
@@ -277,9 +280,8 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
|
|||||||
private boolean shouldEnableBluetooth() {
|
private boolean shouldEnableBluetooth() {
|
||||||
if (bluetoothDecision != BluetoothDecision.ACCEPTED) return false;
|
if (bluetoothDecision != BluetoothDecision.ACCEPTED) return false;
|
||||||
if (hasEnabledBluetooth) return false;
|
if (hasEnabledBluetooth) return false;
|
||||||
Plugin p = pluginManager.getPlugin(BluetoothConstants.ID);
|
if (!isBluetoothSupported()) return false;
|
||||||
if (p == null) return false;
|
State state = bluetoothPlugin.getState();
|
||||||
State state = p.getState();
|
|
||||||
return state == STARTING_STOPPING || state == DISABLED;
|
return state == STARTING_STOPPING || state == DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,6 +300,9 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
|
|||||||
@Override
|
@Override
|
||||||
public void showNextScreen() {
|
public void showNextScreen() {
|
||||||
continueClicked = true;
|
continueClicked = true;
|
||||||
|
if (bluetoothDecision == BluetoothDecision.REFUSED) {
|
||||||
|
bluetoothDecision = BluetoothDecision.UNKNOWN; // Ask again
|
||||||
|
}
|
||||||
if (checkPermissions()) showQrCodeFragmentIfAllowed();
|
if (checkPermissions()) showQrCodeFragmentIfAllowed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,17 +346,17 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
|
|||||||
|
|
||||||
private boolean checkPermissions() {
|
private boolean checkPermissions() {
|
||||||
if (areEssentialPermissionsGranted()) return true;
|
if (areEssentialPermissionsGranted()) return true;
|
||||||
// If the camera permission has been permanently denied, ask the
|
// If an essential permission has been permanently denied, ask the
|
||||||
// user to change the setting
|
// user to change the setting
|
||||||
if (cameraPermission == Permission.PERMANENTLY_DENIED) {
|
if (cameraPermission == Permission.PERMANENTLY_DENIED) {
|
||||||
Builder builder = new Builder(this, R.style.BriarDialogTheme);
|
showDenialDialog(R.string.permission_camera_title,
|
||||||
builder.setTitle(R.string.permission_camera_title);
|
R.string.permission_camera_denied_body);
|
||||||
builder.setMessage(R.string.permission_camera_denied_body);
|
return false;
|
||||||
builder.setPositiveButton(R.string.ok,
|
}
|
||||||
UiUtils.getGoToSettingsListener(this));
|
if (isBluetoothSupported() &&
|
||||||
builder.setNegativeButton(R.string.cancel,
|
locationPermission == Permission.PERMANENTLY_DENIED) {
|
||||||
(dialog, which) -> supportFinishAfterTransition());
|
showDenialDialog(R.string.permission_location_title,
|
||||||
builder.show();
|
R.string.permission_location_denied_body);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Should we show the rationale for one or both permissions?
|
// Should we show the rationale for one or both permissions?
|
||||||
@@ -371,6 +376,16 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showDenialDialog(@StringRes int title, @StringRes int body) {
|
||||||
|
Builder builder = new Builder(this, R.style.BriarDialogTheme);
|
||||||
|
builder.setTitle(title);
|
||||||
|
builder.setMessage(body);
|
||||||
|
builder.setPositiveButton(R.string.ok, getGoToSettingsListener(this));
|
||||||
|
builder.setNegativeButton(R.string.cancel,
|
||||||
|
(dialog, which) -> supportFinishAfterTransition());
|
||||||
|
builder.show();
|
||||||
|
}
|
||||||
|
|
||||||
private void showRationale(@StringRes int title, @StringRes int body) {
|
private void showRationale(@StringRes int title, @StringRes int body) {
|
||||||
Builder builder = new Builder(this, R.style.BriarDialogTheme);
|
Builder builder = new Builder(this, R.style.BriarDialogTheme);
|
||||||
builder.setTitle(title);
|
builder.setTitle(title);
|
||||||
@@ -381,8 +396,13 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void requestPermissions() {
|
private void requestPermissions() {
|
||||||
ActivityCompat.requestPermissions(this,
|
String[] permissions;
|
||||||
new String[] {CAMERA, ACCESS_FINE_LOCATION},
|
if (isBluetoothSupported()) {
|
||||||
|
permissions = new String[] {CAMERA, ACCESS_FINE_LOCATION};
|
||||||
|
} else {
|
||||||
|
permissions = new String[] {CAMERA};
|
||||||
|
}
|
||||||
|
ActivityCompat.requestPermissions(this, permissions,
|
||||||
REQUEST_PERMISSION_CAMERA_LOCATION);
|
REQUEST_PERMISSION_CAMERA_LOCATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,12 +419,15 @@ public abstract class KeyAgreementActivity extends BriarActivity implements
|
|||||||
} else {
|
} else {
|
||||||
cameraPermission = Permission.PERMANENTLY_DENIED;
|
cameraPermission = Permission.PERMANENTLY_DENIED;
|
||||||
}
|
}
|
||||||
if (gotPermission(ACCESS_FINE_LOCATION, permissions, grantResults)) {
|
if (isBluetoothSupported()) {
|
||||||
locationPermission = Permission.GRANTED;
|
if (gotPermission(ACCESS_FINE_LOCATION, permissions,
|
||||||
} else if (shouldShowRationale(ACCESS_FINE_LOCATION)) {
|
grantResults)) {
|
||||||
locationPermission = Permission.SHOW_RATIONALE;
|
locationPermission = Permission.GRANTED;
|
||||||
} else {
|
} else if (shouldShowRationale(ACCESS_FINE_LOCATION)) {
|
||||||
locationPermission = Permission.PERMANENTLY_DENIED;
|
locationPermission = Permission.SHOW_RATIONALE;
|
||||||
|
} else {
|
||||||
|
locationPermission = Permission.PERMANENTLY_DENIED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// If a permission dialog has been shown, showing the QR code fragment
|
// If a permission dialog has been shown, showing the QR code fragment
|
||||||
// on this call path would cause a crash due to
|
// on this call path would cause a crash due to
|
||||||
|
|||||||
@@ -589,6 +589,7 @@
|
|||||||
<string name="permission_camera_location_title">Camera and location</string>
|
<string name="permission_camera_location_title">Camera and location</string>
|
||||||
<string name="permission_camera_location_request_body">To scan the QR code, Briar needs access to the camera.\n\nTo discover Bluetooth devices, Briar needs permission to access your location.\n\nBriar does not store your location or share it with anyone.</string>
|
<string name="permission_camera_location_request_body">To scan the QR code, Briar needs access to the camera.\n\nTo discover Bluetooth devices, Briar needs permission to access your location.\n\nBriar does not store your location or share it with anyone.</string>
|
||||||
<string name="permission_camera_denied_body">You have denied access to the camera, but adding contacts requires using the camera.\n\nPlease consider granting access.</string>
|
<string name="permission_camera_denied_body">You have denied access to the camera, but adding contacts requires using the camera.\n\nPlease consider granting access.</string>
|
||||||
|
<string name="permission_location_denied_body">You have denied access to your location, but Briar needs this permission to discover Bluetooth devices.\n\nPlease consider granting access.</string>
|
||||||
<string name="qr_code">QR code</string>
|
<string name="qr_code">QR code</string>
|
||||||
<string name="show_qr_code_fullscreen">Show QR code fullscreen</string>
|
<string name="show_qr_code_fullscreen">Show QR code fullscreen</string>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user