Refactor more code into AddNearbyContactViewModel

thus concentrating the logic there needing less back and forth with the activity
This commit is contained in:
Torsten Grote
2021-03-23 17:00:36 -03:00
parent bcc0442add
commit 7f486eef4c
8 changed files with 170 additions and 129 deletions

View File

@@ -11,7 +11,6 @@ public interface RequestCodes {
int REQUEST_RINGTONE = 7;
int REQUEST_PERMISSION_CAMERA_LOCATION = 8;
int REQUEST_DOZE_WHITELISTING = 9;
int REQUEST_BLUETOOTH_DISCOVERABLE = 10;
int REQUEST_UNLOCK = 11;
int REQUEST_KEYGUARD_UNLOCK = 12;
int REQUEST_ATTACH_IMAGE = 13;

View File

@@ -1,16 +1,12 @@
package org.briarproject.briar.android.contact.add.nearby;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.MenuItem;
import android.widget.Toast;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.NullSafety;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
@@ -21,25 +17,25 @@ import org.briarproject.briar.android.contact.add.nearby.AddContactState.Failed;
import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
import org.briarproject.briar.android.util.RequestBluetoothDiscoverable;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import androidx.activity.result.ActivityResultLauncher;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider;
import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE;
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.widget.Toast.LENGTH_LONG;
import static java.util.Objects.requireNonNull;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_BLUETOOTH_DISCOVERABLE;
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.ACCEPTED;
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.REFUSED;
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.UNKNOWN;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
@@ -55,14 +51,9 @@ public class AddNearbyContactActivity extends BriarActivity
private AddNearbyContactViewModel viewModel;
private AddNearbyContactPermissionManager permissionManager;
/**
* Set to true in onPostResume() and false in onPause(). This prevents the
* QR code fragment from being shown if onRequestPermissionsResult() is
* called while the activity is paused, which could cause a crash due to
* https://issuetracker.google.com/issues/37067655.
*/
private boolean isResumed = false;
private BroadcastReceiver bluetoothReceiver = null;
private final ActivityResultLauncher<Integer> bluetoothLauncher =
registerForActivityResult(new RequestBluetoothDiscoverable(),
this::onBluetoothDiscoverableResult);
@Override
public void injectActivity(ActivityComponent component) {
@@ -79,21 +70,14 @@ public class AddNearbyContactActivity extends BriarActivity
setContentView(R.layout.activity_fragment_container_toolbar);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
NullSafety.requireNonNull(getSupportActionBar())
.setDisplayHomeAsUpEnabled(true);
requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
if (state == null) {
showInitialFragment(AddNearbyContactIntroFragment.newInstance());
}
IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED);
bluetoothReceiver = new BluetoothStateReceiver();
registerReceiver(bluetoothReceiver, filter);
viewModel.getWasContinueClicked().observe(this, clicked -> {
if (clicked && permissionManager.checkPermissions()) {
showQrCodeFragmentIfAllowed();
}
});
viewModel.getTransportStateChanged().observeEvent(this,
t -> showQrCodeFragmentIfAllowed());
viewModel.getCheckPermissions().observeEvent(this, check ->
permissionManager.checkPermissions()); // never false
viewModel.getRequestBluetoothDiscoverable().observeEvent(this, r ->
requestBluetoothDiscoverable()); // never false
viewModel.getShowQrCodeFragment().observeEvent(this, show -> {
if (show) showQrCodeFragment();
});
@@ -113,37 +97,23 @@ public class AddNearbyContactActivity extends BriarActivity
@Override
protected void onPostResume() {
super.onPostResume();
isResumed = true;
// Workaround for
// https://code.google.com/p/android/issues/detail?id=190966
showQrCodeFragmentIfAllowed();
viewModel.setIsActivityResumed(true);
}
@Override
protected void onPause() {
super.onPause();
isResumed = false;
viewModel.setIsActivityResumed(false);
}
@Override
public void onDestroy() {
super.onDestroy();
if (bluetoothReceiver != null) unregisterReceiver(bluetoothReceiver);
}
@Override
public void onActivityResult(int request, int result,
@Nullable Intent data) {
if (request == REQUEST_BLUETOOTH_DISCOVERABLE) {
if (result == RESULT_CANCELED) {
LOG.info("Bluetooth discoverability was refused");
viewModel.bluetoothDecision = REFUSED;
} else {
LOG.info("Bluetooth discoverability was accepted");
viewModel.bluetoothDecision = ACCEPTED;
}
showQrCodeFragmentIfAllowed();
} else super.onActivityResult(request, result, data);
private void onBluetoothDiscoverableResult(boolean discoverable) {
if (discoverable) {
LOG.info("Bluetooth discoverability was accepted");
viewModel.setBluetoothDecision(ACCEPTED);
} else {
LOG.info("Bluetooth discoverability was refused");
viewModel.setBluetoothDecision(REFUSED);
}
}
@Override
@@ -161,14 +131,16 @@ public class AddNearbyContactActivity extends BriarActivity
super.onRequestPermissionsResult(requestCode, permissions,
grantResults);
permissionManager.onRequestPermissionsResult(requestCode, permissions,
grantResults, this::showQrCodeFragmentIfAllowed);
grantResults, viewModel::showQrCodeFragmentIfAllowed);
}
@Override
public void onBackPressed() {
if (viewModel.getState().getValue() instanceof Failed) {
// finish this activity when going back in failed state
supportFinishAfterTransition();
// re-create this activity when going back in failed state
Intent i = new Intent(this, AddNearbyContactActivity.class);
i.setFlags(FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
} else {
super.onBackPressed();
}
@@ -176,41 +148,15 @@ public class AddNearbyContactActivity extends BriarActivity
private void requestBluetoothDiscoverable() {
if (!viewModel.isBluetoothSupported()) {
viewModel.bluetoothDecision = BluetoothDecision.NO_ADAPTER;
showQrCodeFragmentIfAllowed();
viewModel.setBluetoothDecision(BluetoothDecision.NO_ADAPTER);
} else {
Intent i = new Intent(ACTION_REQUEST_DISCOVERABLE);
if (i.resolveActivity(getPackageManager()) != null) {
LOG.info("Asking for Bluetooth discoverability");
viewModel.bluetoothDecision = BluetoothDecision.WAITING;
startActivityForResult(i, REQUEST_BLUETOOTH_DISCOVERABLE);
viewModel.setBluetoothDecision(BluetoothDecision.WAITING);
bluetoothLauncher.launch(120); // 2min discoverable
} else {
viewModel.bluetoothDecision = BluetoothDecision.NO_ADAPTER;
showQrCodeFragmentIfAllowed();
}
}
}
@SuppressWarnings("StatementWithEmptyBody")
private void showQrCodeFragmentIfAllowed() {
boolean continueClicked = // never set to null
NullSafety.requireNonNull(
viewModel.getWasContinueClicked().getValue());
boolean permissionsGranted =
permissionManager.areEssentialPermissionsGranted();
if (isResumed && continueClicked && permissionsGranted) {
if (viewModel.isWifiReady() && viewModel.isBluetoothReady()) {
LOG.info("Wifi and Bluetooth are ready");
viewModel.startAddingContact();
} else {
viewModel.enableWifiIfWeShould();
if (viewModel.bluetoothDecision == UNKNOWN) {
requestBluetoothDiscoverable();
} else if (viewModel.bluetoothDecision == REFUSED) {
// Ask again when the user clicks "continue"
} else {
viewModel.enableBluetoothIfWeShould();
}
viewModel.setBluetoothDecision(BluetoothDecision.NO_ADAPTER);
}
}
}
@@ -233,11 +179,6 @@ public class AddNearbyContactActivity extends BriarActivity
((ContactExchangeFinished) state).result;
onContactExchangeResult(result);
} else if (state instanceof Failed) {
// Remove navigation icon, so user can't go back when failed
// ErrorFragment will finish or relaunch this activity
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setNavigationIcon(null);
Boolean qrCodeTooOld = ((Failed) state).qrCodeTooOld;
onAddingContactFailed(qrCodeTooOld);
}
@@ -286,11 +227,4 @@ public class AddNearbyContactActivity extends BriarActivity
showNextFragment(new AddNearbyContactErrorFragment());
}
private class BluetoothStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
LOG.info("Bluetooth scan mode changed");
showQrCodeFragmentIfAllowed();
}
}
}

View File

@@ -171,10 +171,8 @@ public class AddNearbyContactFragment extends BaseFragment
status.setText(R.string.waiting_for_contact_to_scan);
} else if (state instanceof KeyAgreementStarted) {
qrCodeView.setVisibility(INVISIBLE);
statusView.setVisibility(VISIBLE);
status.setText(R.string.authenticating_with_device);
} else if (state instanceof ContactExchangeStarted) {
statusView.setVisibility(VISIBLE);
status.setText(R.string.exchanging_contact_details);
} else if (state instanceof Failed) {
// the activity will replace this fragment with an error fragment

View File

@@ -1,5 +1,7 @@
package org.briarproject.briar.android.contact.add.nearby;
import android.content.Context;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.BaseActivity;
@@ -11,6 +13,8 @@ import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.Manifest.permission.CAMERA;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale;
import static androidx.core.content.ContextCompat.checkSelfPermission;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PERMISSION_CAMERA_LOCATION;
import static org.briarproject.briar.android.util.UiUtils.getGoToSettingsListener;
@@ -37,6 +41,15 @@ class AddNearbyContactPermissionManager {
locationPermission = Permission.UNKNOWN;
}
static boolean areEssentialPermissionsGranted(Context ctx,
boolean isBluetoothSupported) {
int ok = PERMISSION_GRANTED;
return checkSelfPermission(ctx, CAMERA) == ok &&
(SDK_INT < 23 ||
checkSelfPermission(ctx, ACCESS_FINE_LOCATION) == ok ||
!isBluetoothSupported);
}
boolean areEssentialPermissionsGranted() {
return cameraPermission == Permission.GRANTED &&
(SDK_INT < 23 || locationPermission == Permission.GRANTED ||
@@ -147,8 +160,7 @@ class AddNearbyContactPermissionManager {
}
private boolean shouldShowRationale(String permission) {
return ActivityCompat
.shouldShowRequestPermissionRationale(ctx, permission);
return shouldShowRequestPermissionRationale(ctx, permission);
}
}

View File

@@ -2,6 +2,10 @@ package org.briarproject.briar.android.contact.add.nearby;
import android.app.Application;
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.util.DisplayMetrics;
import android.widget.Toast;
@@ -39,6 +43,7 @@ import org.briarproject.bramble.api.plugin.PluginManager;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.plugin.event.TransportStateEvent;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.briar.R;
import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeFinished;
import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeResult.Error;
@@ -64,6 +69,7 @@ import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
import static android.widget.Toast.LENGTH_LONG;
import static java.util.Objects.requireNonNull;
@@ -75,6 +81,7 @@ import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED;
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.util.LogUtils.logException;
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactPermissionManager.areEssentialPermissionsGranted;
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.REFUSED;
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.UNKNOWN;
@@ -116,6 +123,7 @@ class AddNearbyContactViewModel extends AndroidViewModel
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
private final EventBus eventBus;
private final AndroidExecutor androidExecutor;
private final Executor ioExecutor;
private final PluginManager pluginManager;
private final PayloadEncoder payloadEncoder;
@@ -124,28 +132,28 @@ class AddNearbyContactViewModel extends AndroidViewModel
private final ContactExchangeManager contactExchangeManager;
private final ConnectionManager connectionManager;
/**
* Set to true when the continue button is clicked, and false when the QR
* code fragment is shown. This prevents the QR code fragment from being
* shown automatically before the continue button has been clicked.
*/
private final MutableLiveData<Boolean> wasContinueClicked =
new MutableLiveData<>(false);
private final MutableLiveEvent<Boolean> showQrCodeFragment =
private final MutableLiveEvent<Boolean> checkPermissions =
new MutableLiveEvent<>();
private final MutableLiveEvent<TransportId> transportStateChanged =
private final MutableLiveEvent<Boolean> requestBluetoothDiscoverable =
new MutableLiveEvent<>();
private final MutableLiveEvent<Boolean> showQrCodeFragment =
new MutableLiveEvent<>();
private final MutableLiveData<AddContactState> state =
new MutableLiveData<>();
final QrCodeDecoder qrCodeDecoder;
final BroadcastReceiver bluetoothReceiver = new BluetoothStateReceiver();
@Nullable
private final BluetoothAdapter bt;
@Nullable
private final Plugin wifiPlugin, bluetoothPlugin;
// UiThread
BluetoothDecision bluetoothDecision = BluetoothDecision.UNKNOWN;
private BluetoothDecision bluetoothDecision = BluetoothDecision.UNKNOWN;
private boolean wasContinueClicked = false;
private boolean isActivityResumed = false;
/**
* Records whether we've enabled the wifi plugin so we don't enable it more
@@ -166,6 +174,7 @@ class AddNearbyContactViewModel extends AndroidViewModel
@Inject
AddNearbyContactViewModel(Application app,
EventBus eventBus,
AndroidExecutor androidExecutor,
@IoExecutor Executor ioExecutor,
PluginManager pluginManager,
PayloadEncoder payloadEncoder,
@@ -175,6 +184,7 @@ class AddNearbyContactViewModel extends AndroidViewModel
ConnectionManager connectionManager) {
super(app);
this.eventBus = eventBus;
this.androidExecutor = androidExecutor;
this.ioExecutor = ioExecutor;
this.pluginManager = pluginManager;
this.payloadEncoder = payloadEncoder;
@@ -185,13 +195,16 @@ class AddNearbyContactViewModel extends AndroidViewModel
bt = BluetoothAdapter.getDefaultAdapter();
wifiPlugin = pluginManager.getPlugin(LanTcpConstants.ID);
bluetoothPlugin = pluginManager.getPlugin(BluetoothConstants.ID);
qrCodeDecoder = new QrCodeDecoder(ioExecutor, this);
qrCodeDecoder = new QrCodeDecoder(androidExecutor, ioExecutor, this);
eventBus.addListener(this);
IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED);
getApplication().registerReceiver(bluetoothReceiver, filter);
}
@Override
protected void onCleared() {
super.onCleared();
getApplication().unregisterReceiver(bluetoothReceiver);
eventBus.removeListener(this);
stopListening();
}
@@ -201,7 +214,9 @@ class AddNearbyContactViewModel extends AndroidViewModel
if (bluetoothDecision == REFUSED) {
bluetoothDecision = UNKNOWN; // Ask again
}
wasContinueClicked.setValue(true);
wasContinueClicked = true;
checkPermissions.setEvent(true);
showQrCodeFragmentIfAllowed();
}
@UiThread
@@ -266,7 +281,7 @@ class AddNearbyContactViewModel extends AndroidViewModel
void startAddingContact() {
// If we return to the intro fragment, the continue button needs to be
// clicked again before showing the QR code fragment
wasContinueClicked.setValue(false);
wasContinueClicked = false;
// If we return to the intro fragment, ask for Bluetooth
// discoverability again before showing the QR code fragment
bluetoothDecision = UNKNOWN;
@@ -310,12 +325,12 @@ class AddNearbyContactViewModel extends AndroidViewModel
if (LOG.isLoggable(INFO)) {
LOG.info("Bluetooth state changed to " + t.getState());
}
transportStateChanged.setEvent(t.getTransportId());
showQrCodeFragmentIfAllowed();
} else if (t.getTransportId().equals(LanTcpConstants.ID)) {
if (LOG.isLoggable(INFO)) {
LOG.info("Wifi state changed to " + t.getState());
}
transportStateChanged.setEvent(t.getTransportId());
showQrCodeFragmentIfAllowed();
}
} else if (e instanceof KeyAgreementListeningEvent) {
LOG.info("KeyAgreementListeningEvent received");
@@ -344,6 +359,28 @@ class AddNearbyContactViewModel extends AndroidViewModel
}
}
@SuppressWarnings("StatementWithEmptyBody")
@UiThread
void showQrCodeFragmentIfAllowed() {
boolean permissionsGranted = areEssentialPermissionsGranted(
getApplication(), isBluetoothSupported());
if (isActivityResumed && wasContinueClicked && permissionsGranted) {
if (isWifiReady() && isBluetoothReady()) {
LOG.info("Wifi and Bluetooth are ready");
startAddingContact();
} else {
enableWifiIfWeShould();
if (bluetoothDecision == UNKNOWN) {
requestBluetoothDiscoverable.setEvent(true);
} else if (bluetoothDecision == REFUSED) {
// Ask again when the user clicks "continue"
} else {
enableBluetoothIfWeShould();
}
}
}
}
/**
* This sets the QR code by setting the state to KeyAgreementListening.
*/
@@ -383,8 +420,8 @@ class AddNearbyContactViewModel extends AndroidViewModel
state.postValue(new AddContactState.Failed(e.isTooOld()));
} catch (IOException | IllegalArgumentException e) {
LOG.log(WARNING, "QR Code Invalid", e);
Toast.makeText(getApplication(), R.string.qr_code_invalid,
LENGTH_LONG).show();
androidExecutor.runOnUiThread(() -> Toast.makeText(getApplication(),
R.string.qr_code_invalid, LENGTH_LONG).show());
resetPayloadFlags();
state.postValue(new AddContactState.Failed());
}
@@ -423,6 +460,15 @@ class AddNearbyContactViewModel extends AndroidViewModel
});
}
private class BluetoothStateReceiver extends BroadcastReceiver {
@UiThread
@Override
public void onReceive(Context context, Intent intent) {
LOG.info("Bluetooth scan mode changed");
showQrCodeFragmentIfAllowed();
}
}
private void tryToClose(DuplexTransportConnection conn) {
try {
conn.getReader().dispose(true, true);
@@ -432,16 +478,33 @@ class AddNearbyContactViewModel extends AndroidViewModel
}
}
LiveData<Boolean> getWasContinueClicked() {
return wasContinueClicked;
/**
* Set to true in onPostResume() and false in onPause(). This prevents the
* QR code fragment from being shown if onRequestPermissionsResult() is
* called while the activity is paused, which could cause a crash due to
* https://issuetracker.google.com/issues/37067655.
* TODO check if this is still happening when using new permission requesting
*/
@UiThread
void setIsActivityResumed(boolean resumed) {
isActivityResumed = resumed;
// Workaround for
// https://code.google.com/p/android/issues/detail?id=190966
showQrCodeFragmentIfAllowed();
}
/**
* Receives an event when the transport state of the WiFi or Bluetooth
* plugins changes.
*/
LiveEvent<TransportId> getTransportStateChanged() {
return transportStateChanged;
@UiThread
void setBluetoothDecision(BluetoothDecision decision) {
bluetoothDecision = decision;
showQrCodeFragmentIfAllowed();
}
LiveEvent<Boolean> getCheckPermissions() {
return checkPermissions;
}
LiveEvent<Boolean> getRequestBluetoothDiscoverable() {
return requestBluetoothDiscoverable;
}
LiveEvent<Boolean> getShowQrCodeFragment() {

View File

@@ -18,6 +18,7 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.system.AndroidExecutor;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
@@ -35,6 +36,7 @@ class QrCodeDecoder implements PreviewConsumer, PreviewCallback {
private static final Logger LOG = getLogger(QrCodeDecoder.class.getName());
private final AndroidExecutor androidExecutor;
private final Executor ioExecutor;
private final Reader reader = new QRCodeReader();
private final ResultCallback callback;
@@ -42,7 +44,9 @@ class QrCodeDecoder implements PreviewConsumer, PreviewCallback {
private Camera camera = null;
private int cameraIndex = 0;
QrCodeDecoder(@IoExecutor Executor ioExecutor, ResultCallback callback) {
QrCodeDecoder(AndroidExecutor androidExecutor,
@IoExecutor Executor ioExecutor, ResultCallback callback) {
this.androidExecutor = androidExecutor;
this.ioExecutor = ioExecutor;
this.callback = callback;
}
@@ -104,9 +108,9 @@ class QrCodeDecoder implements PreviewConsumer, PreviewCallback {
LOG.warning("Invalid preview frame");
} finally {
reader.reset();
androidExecutor.runOnUiThread(this::askForPreviewFrame);
}
});
askForPreviewFrame();
}
private static BinaryBitmap binarize(byte[] data, int width, int height,

View File

@@ -0,0 +1,31 @@
package org.briarproject.briar.android.util;
import android.content.Context;
import android.content.Intent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.annotation.Nullable;
import static android.app.Activity.RESULT_CANCELED;
import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE;
import static android.bluetooth.BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION;
@NotNullByDefault
public class RequestBluetoothDiscoverable
extends ActivityResultContract<Integer, Boolean> {
@Override
public Intent createIntent(Context context, Integer duration) {
Intent i = new Intent(ACTION_REQUEST_DISCOVERABLE);
i.putExtra(EXTRA_DISCOVERABLE_DURATION, duration);
return i;
}
@Override
public Boolean parseResult(int resultCode, @Nullable Intent intent) {
return resultCode != RESULT_CANCELED;
}
}

View File

@@ -4,7 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".android.contact.add.nearby.KeyAgreementActivity">
tools:context=".android.contact.add.nearby.AddNearbyContactActivity">
<include layout="@layout/toolbar" />